【python】其他

函数参数

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,
这5种参数都可以组合使用。
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
------------------------------------
如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:

>>> nums = [1, 2, 3]
>>> calc(nums[0], nums[1], nums[2])
14
这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:

>>> nums = [1, 2, 3]
>>> calc(*nums)
14
*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
------------------------------------
和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, city=extra['city'], job=extra['job'])
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
当然,上面复杂的调用可以用简化的写法:

>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,
kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。

深拷贝和浅拷贝

在python中,有深拷贝(deep copy) 和 浅拷贝 的区别。

简单来讲就是:深拷贝就是把要拷贝的对象整体复制一份,存在新开辟的空间里;

而浅拷贝指的是,对于要拷贝的对象要复制一份,但是对于其内部的子对象就不复制了,

而是直接引用,也就是类似于添加了一个链接而已。

装饰器

装饰器

装饰器本质上是一个 Python 函数或类,它可以在不修改其他函数或类的代码前提下增加额外功能,

也不需要对函数和类的调用做修改。

同时它可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。

装饰器的返回值也是一个函数/类对象。

Python 中的函数可以像普通变量一样当做参数传递给另外一个函数,例如:

def use_logging(func):
    logging.warn("%s is running" % func.__name__)
    func()
 
def foo():
    print('i am foo')
 
use_logging(foo)

def use_logging(func):
 
    def wrapper():
        logging.warn("%s is running" % func.__name__)
        func()   # 把 foo 当做参数传递进来时,执行func()就相当于执行foo()
    return wrapper
 
def foo():
    print('i am foo')
 
foo = use_logging(foo)  
#因为装饰器use_logging(foo) 返回的时函数对象wrapper,这条语句相当于foo = wrapper
foo()              
#执行foo()就相当于执行 wrapper()

use_logging 就是一个装饰器,它是一个普通的函数,它把执行真正业务逻辑的函数 func 包裹在其中,

看起来像 foo 被 use_logging 装饰了一样,use_logging 返回的也是一个函数,这个函数的名字叫 wrapper。

在这个例子中,函数进入和退出时,被称为一个横切面,这种编程方式被称为面向切面的编程。

@ 语法糖

@ 符号就是装饰器的语法糖,它放在函数开始定义的地方,这样就可以省略最后一步再次赋值的操作。


def use_logging(func):
 
    def wrapper():
        logging.warn("%s is running" % func.__name__)
        return func()
    return wrapper
 
@use_logging
def foo():
    print("i am foo")
 
foo()

如上所示,有了 @ ,我们就可以省去foo = use_logging(foo)这一句了,直接调用 foo() 即可得到想要的结果。

foo() 函数不需要做任何修改,只需在定义的地方加上装饰器,调用的时候还是和以前一样,

如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。

这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

装饰器在 Python 使用如此方便都要归因于 Python 的函数能像普通的对象一样能作为参数传递给其他函数,

可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

*args、**kwargs

可能有人问,如果我的业务逻辑函数 foo 需要参数怎么办?比如:

def foo(name):
    print("i am %s" % name)

我们可以在定义 wrapper 函数的时候指定参数:


def wrapper(name):
    logging.warn("%s is running" % func.__name__)
    func(name)
return wrapper

这样 foo 函数定义的参数就可以定义在 wrapper 函数中。

这时,又有人要问了,如果 foo 函数接收两个参数呢?三个参数呢?

更有甚者,我可能传很多个。当装饰器不知道 foo 到底有多少个参数时,我们可以用 *args 来代替:

def wrapper(*args):
    logging.warn("%s is running" % func.__name__)
    func(*args)
return wrapper

同样可以指定关键字参数

def wrapper(*args, **kwargs):
# args是一个元组,kwargs一个字典
    logging.warn("%s is running" % func.__name__)
    func(*args, **kwargs)
return wrapper

带参数的装饰器

类装饰器

装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。

使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

装饰器顺序

一个函数可以同时定义多个装饰器,比如:

@a
@b
@c
def f ():
    pass

它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于

f = a(b(c(f)))

单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,

该模式的主要目的是确保某一个类只有一个实例存在。

当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

1、使用模块,在模块中实例化类对象,导入这个实例化对象即可;

2、使用装饰器,在装饰器函数中判断是否已经实例化;

3、重写__new__方法:

当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__)实例化对象

然后再执行类的__init__方法,对这个对象进行初始化

4、基于metaclass方式实现

多线程

猜你喜欢

转载自blog.csdn.net/weixin_39723165/article/details/81516603