文章目录
一、 闭包
定义:外部函数中定义一个内部函数,内部函数引用外部函数中的变量,外部函数的返回值是内部函数。
闭包与装饰器区别:
-
闭包传递的是变量,而装饰器传递的是函数;
-
除此之外没有任何区别,或者说装饰器是闭包的一种,它只是传递函数的闭包。
闭包的简单示例:
def out(i):
def inner(j):
return i*j
return inner
#调用闭包
res = out(2) # i=2
print(res(10)) # j=10
# 输出20
当内函数中需要修改外函数的值时:
用nonlocal 关键字声明一个变量,表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量。
注意:使用闭包的过程中,一旦外函数被调用一次返回了内函数的引用,虽然每次调用内函数,是开启一个函数执行过后消亡,但是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量。
以下代码中的x即为第一次调用后修改过的x:
在闭包中引用循环变量:
二、装饰器
装饰器本质上是一个可调用的对象,一般由函数、类来实现,主要用途是包装另一个函数或类。
好处:在不用更改原函数的代码前提下给函数增加新的功能。
多个装饰器时:
装饰器接受参数:
类装饰器也相当于一种函数,它接受类作为输入并返回类作为输出:
三、带参数的装饰器
(1)带固定参数的装饰器:
(2)带不定参数的装饰器:
(3)装饰器带参数:
四、 装饰器的使用场景
(1)时间计时器
def timer(func):
def wrapper(*args,**kwargs):
t1 = time.time()
func(*args,**kwargs)
t2 = time.time()
cost_time = t2 -t1
print("花费时间:{}秒".format(cost_time))
return wrapper
(2)日志打印器
def logger(func):
def wrapper(*args,**kwargs):
print("准备开始计算:{}函数".format(func.__name__))
func(*args,**kwargs)
print("计算完成")
(3)@staticmethod 和 @classmethod 的 区别 和 使用场景:
@classmethod装饰的类方法里面,会传一个cls参数,代表本类,这样就能够避免手写类名的硬编码。
使用场景:
在定义类的时候,假如不需要用到与类相关的属性或方法时,就用静态方法@staticmethod;
假如需要用到与类相关的属性或方法,然后又想表明这个方法是整个类通用的,而不是对象特异的,就可以使用类方法@classmethod。
五、三个内置装饰器:staticmethod、classmethod、property
1、staticmethod
2、classmethod 类装饰器
3、property类静态属性装饰器。 把类的方法伪装成属性
1和2都可以用 类名.方法名 进行直接调用,而不用创建实例对象;
两者区别:
- classmethod是需要cls参数的,cls和self一样,代表类本身,但是 cls不能调用实例对象的属性,即不能调用def __ init __ 下面的属性。可以通过 cls.类属性 或 cls.类方法 来调用类的属性和方法。
- staticmethod不需要self和cls参数,它注重的是类的静态变量,跟类的实例化对象没有关系,所以它 也不能调用类实例化对象的属性,即def __ init __ 下面的属性,而且只能通过 类名.类属性,类名.类方法 来调用类的属性和方法。
举例:
#classmethod, staticmethod
class my_class():
__pwd = 123456
def __init__(self):
self.name = '老六'
@classmethod
def func1(cls):
#不能调用实例对象的属性,可以通过cls调用类的属性
print("this is func1")
print(cls.__pwd)
@staticmethod
def func2():
#不能调用实例对象的属性,只能调用类的属性
print("this is func2")
print(my_class.__pwd)
def func3(self):
#可以调用实例对象的属性,也可以调用类的属性
print("this is func3")
print(self.__pwd)
print(self.name)
#func1有classmethod装饰,func2有staticmethod,func3没有进行任何装饰
my_class.func1()
my_class.func2()
#需要创建实例对象才能调用func3
my_class().func3()
>>>
this is func1
123456
this is func2
123456
this is func3
123456
老六
1、staticmethod:
将类中的方法装饰为静态方法,即类不需要创建实例的情况下,可以通过类名直接引用。到达将函数功能与实例解绑的效果。
2、classmethod 类方法
类方法的第一个参数是一个类,是将类本身作为操作的方法。类方法被哪个类调用,就传入哪个类作为第一个参数进行操作。参数写slef或cls都行。。可以不用创建实例对象直接进行类名.类方法调用(见第二个举例)。
不需要self参数:但第一个参数需要是表示自身类的 cls 参数
3、property:
property一般有两个作用,如下:
- 作为装饰器,@property 将类的方法转为只读的类属性。
例如:它把sayHello方法变成了一个属性,使用的是cls.sayHello而不是cls.sayHello()。 - property 重新实现一个属性的 getter 和 setter 方法。
适应场景:
1.只读不可修改的属性。只需要实现@property
2.输入对setter进行判断。
3.需要实时地计算属性值。
*args和**kwargs区别:
*args代表任何多个无名参数,返回的是元组;**kwargs表示关键字参数,所有传入的key=value,返回字典;
下面@property 重新实现一个私有属性的 getter 和 setter 方法。
class E():
__name = '张三'
def __init__(self):
self.__age = 23
self.__luange = 'python'
def __method(self):
print("我叫{},今年{}岁,我喜欢{}。".format(self.__name, self.__age, self.__luange))
@property
def name(self):
return self.__name
@name.setter
def name(self, name):
self.__name = name
if __name__ == '__main__':
e = E()
#访问
print(e.name)
#修改
print("修改前:", e.name)
e.name = '隔壁老王'
print("修改后:", e.name)
>>>
张三
修改前: 张三
修改后: 隔壁老王