闭包:
闭包 :一个函数里面嵌套一个函数,调用外层函数返回里层函数本身
示例1:
def fx(x):
x +=1
def fy(y):
return x*y
return fy # 不要加括号
f = fx(5) # fy
n = f(5) #fy()
print(n) #30
示例2(入参是一个函数):
def f1(f2):
print("f1执行")
def f3(b):
print("f3执行",f2(b)+1)
return f3
def f2(a):
return a+a
f=f1(f2)# f3
f(4)# f3()
#可以直接f=f1(f2)(4)
执行结果:
f1执行
f3执行 9
装饰器:
装饰函数的参数是被装饰的函数对象,返回原函数对象装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
示例1(还是刚才的f1,f2):
def f1(f2):
print("f1执行")
def f3(b):
print("f3执行",f2(b)+1)
return f3
@f1
def f2(a):
return a+a
f2(4)#9
#本来f2是计算一个数的平方,现在加了一个@f1修饰就成一个数的平方+1了。
在f2上加一个@f1,f1就是装饰器,而刚才演示的闭包的实现原理就是装饰器实现的原理。也可以说装饰器也是闭包。
还有一个更好诠释装饰器的例子:
#计算一个函数运行的时间:
import time
def countTime(fun):
def count(*args,**kwargs):
t1=time.time()
print("开始时间:",t1)
back=fun(*args,**kwargs)
t2=time.time()
print("结束时间:",t2)
print("总用时:",t2-t1)
return back
return count
@countTime
def f(a):
for i in range(a):
print(i)
f(1000)
#输出结果:
'''
开始时间: 1517415914.1400516
1
2
...
999
结束时间: 1517415914.144096
总用时: 0.004044294357299805
'''
类装饰器
把一个类装饰到一个函数上。
示例:
class Tset_Class():
def __init__(self,func):
print('正在实例化')
self.func = func
def __call__(self, *args, **kwargs): # 一定要写这个call
print('这是call方法')
return self.func
@Tset_Class
def test():
print('这是一个测试函数')
n = test() # self.func : test 函数体
n() #这是一个测试函数
类装饰器的执行过程:
# 1. @Tset_Class : Tset_Class( test ) -> 相当于:t = Tset_Class( test )
# 2. test() -> 相当于: t() 调用实例的call方法 -> 返回 self.func函数体
# 3. n = test() ,n() 调用test()
通过2.知道必须要写call方法
三个常用的装饰器
@property
装饰过的函数返回的不再是一个函数,而是一个property对象
装饰过后的方法不再是可调用的对象,可以看做数据属性直接访问。
示例:
class Test():
def __init__(self,name):
self.__name = name
@property # 把方法变成属性
def get_name(self):
return self.__name
@get_name.setter # 可以让get方法,变成set方法
def get_name(self,name):
self.__name = name
@property # 把方法变成属性
def po(self):
print('asdfasdfasdfasdaf')
t = Test('xfy')
print(t.get_name)#xfy
t.get_name = "stefan" #stefan
print(t.get_name)
t.po#123
Test类里有一个私有属性__name
,这样在外界是不能访问的,曾经我们通过写一个get_name
方法来获得__name
的值,但是每次调用都是t.get_name()
,现在加了@property
,让这个方法变成像一个属性一样访问。
再加一个这样的@get_name.setter
,就具备了赋值的能力。
@staticmethod #(静态方法)
@classmethod (类方法)
这两个装饰器详情请见Python学习之面向对象(封装、继承、多态)
对于装饰器的学习本篇只是初步,它的用途很大,主要作用就是权限控制,插入日志,性能测试,事务处理,缓存等。
还得等实际项目中碰到了,再深入学习。
有任何疑问,请留言评论。