一、闭包的定义:
闭包函数需要满足三个条件才是闭包:
- 函数内部嵌套一个函数;
- 外层函数返回内层函数的函数名;
- 内层函数对外部作用域,至少有一个非全局变量的引用...
例子NO.1
def func(b): #参数b也是外部作用域的非全局变量
a=100 #a为外部作用域的非全局变量
def wrapper(): #嵌套函数
print(b*200) #对外部函数的引用
print(a+100)
print('hello,这是内层函数的嵌套函数')
return wrapper #返回内层函数
c=func(2)
print(c)
c()
运行结果:
>>
<function func.<locals>.wrapper at 0x0000026E640B47B8>
400
200
hello,这是内层函数的嵌套函数
>>
=================================================
例子NO.2
def func(b):
a=100
def wrapper():
print('----wrapper----')
b() #直接调用所传入的功能函数
print('hello,这是内层函数的嵌套函数')
return wrapper
def user_info():
print('这个是显示个人信息的功能函数')
f=func(user_info) #传入的参数为一个功能函数
f()
运行结果:
>>
----wrapper----
这个是显示个人信息的功能函数
hello,这是内层函数的嵌套函数
<<
判断是否是闭包函数:是闭包则返回cell,不是则返回None
def outer():
money = 0
def inner():
nonlocal money
money += 100
print(money)
return inner
res = outer()
res()
print(res.__closure__)
print(outer().__closure__)
===============================================
(<cell at 0x000001CBECE59138: int object at 0x00007FF92573EFB0>,)
(<cell at 0x000001CBFD6008E8: int object at 0x00007FF92573E330>,)
二、一般装饰器
闭包函数就是种装饰器
1)无参数的装饰器
例子NO.1
def func(b):
a=100
def wrapper():
print('----wrapper----')
b()
print('hello,这是内层函数的嵌套函数')
return wrapper
@func #==> user_info = func(user_info)
def user_info():
print('这个是显示个人信息的功能函数')
user_info() # 加了装饰器func(),这里直接调用就可以
运行结果:
>>
----wrapper----
这个是显示个人信息的功能函数
hello,这是内层函数的嵌套函数
<<
=================================================
例子NO.2
#装饰器函数
def decorator(func): #装饰器函数必须传参
def wrapper():
#再这里可以写装饰器扩展的新功能
user=input('账号:')
pwd=input('密码:')
if user=='python' and pwd=='123':
print('账号密码正确,调用原来的功能函数')
func()
else:
print('账号密码错误~!')
return wrapper
@decorator #相当于调用 user_info=decorator(user_info)
def user_info():
print('这个是显示个人信息的功能函数')
user_info()
2)内部函数有参数的装饰器
def decorator(func):
# 如果被装饰的函数带有参数,那么内函数必须也有对应数量的的参数
# 因为调用原函数,等于调用内函数
def wrapper(a,b):
print('打印两个数相减的结果',a-b)
func(a,b) #调用的是add_number函数,所以要传参
return wrapper
@decorator #==>add_number=decorator(add_number)
def add_number(a,b):
print('两个数相加的结果',a+b)
add_number(2,3)
运行结果:
>>
打印两个数相减的结果 -1
两个数相加的结果 5
<<
如果被装饰的函数带有参数,那么内函数必须也有对应数量的的参数
因为调用原函数,等于调用内函数
3)外部函数有参数的装饰器
如果装饰器需要有参数,那么给当前的装饰器套一个壳,用于接受装饰器的参数
def insert_var(value):
def outer(func):
def inner1():
print(f'参数{value}:妹子给了你微信')
func()
def inner2():
print(f'参数{value}:妹子给介绍了个白富美')
func()
# 装饰器壳的参数,可以用于在函数内做流程控制
if value == "白富美":
return inner2
else:
return inner1
return outer
@insert_var('白富美')
def love():
print('淡淡人生')
love()
结果:
参数白富美:妹子给介绍了个白富美
淡淡人生
三、高阶装饰器
1)无参数的类装饰器
Python中有一个有趣的语法,只要定义类型的时候,实现__call__函数,这个类型就成为可调用的。换句话说,我们可以
把这个类型的对象当作函数来使用,相当于 重载了括号运算符。
NO.1
class logger(object):
def __init__(self,func):
self.func=func
def __call__(self, *args, **kwargs): #__call__方法接收被装饰函数,实现装饰逻辑。
print("[INFO]:the function {func}() is running...".format(func=self.func.__name__))
return self.func(*args,**kwargs)
@logger
def say(something):
print('say{}!'.format(something))
say('hello')
NO.2
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __call__(self, friend):
print 'My name is %s...' % self.name
print 'My friend is %s...' % friend
#现在可以对 Person 实例直接调用:
p=Person('Bob','Male')
p('Lily')
运行结果:
==>my name is Bob
my friend is lily
NO.3
class Outer:
# 魔术方法:当把该类的对象当作函数调用时,自动触发obj()
def __call__(self, func):
self.func = func
return self.inner
def inner(self, who):
print('拿到了妹子的微信')
self.func(who)
print('看了一场午夜电影')
@Outer()
def love(who):
print(f'{who}和妹子谈谈人生。。。。')
love('lisa')
==>运行结果:
拿到了妹子的微信
lisa和妹子谈谈人生。。。。
看了一场午夜电影
2)三大内置装饰器之一:描述符 property
NO.1 property的只读性
class person():
def __init__(self,name,age=18):
self.name=name
self.__age=18
@property
def age(self):
return self.__age
xm=person('lily') #实例化
print(xm.age) #结果为18
xm.age=22 #报错无法给年龄赋值
print(xm.age)
==>运行结果:
xm.age=22
AttributeError: can't set attribute
18
NO.2 用@property装饰过的函数,会将一个函数定义成一个属性,属性的值就是该函
数return的内容。同时,会将这个函数变成另外一个装饰器。就像后面我们使用的@age.setter和@age.deleter
class student():
def __init__(self,name):
self.name=name
self.name=None
@property
def age(self): #该方法函数为student的一个属性,属性的值就是该函数
return self._age
@age.setter #age函数变成另外一个装饰器
def age(self,value):
if not isinstance(value,int):
raise ValueError('输入不合法,年龄必须为整数!')
if not 0<value<100:
raise ValueError('输入不合法,年龄必须0~100')
self._age=value #给装饰器property的函数赋值,将形参传递的实参赋给函数
@age.deleter
def age(self):
del self._age
xiaoming=student('小明')
xiaoming.age=11
print(xiaoming.age)
del xiaoming.age
print(xiaoming.age)
四、嵌套装饰器
def test1(f):
def inner():
print('成功拿到妹子的微信....3')
f()
print('成功约到妹子看电影....4')
return inner
def test2(f):
def inner():
print('我是扩展1')
f()
print('我是扩展2')
return inner
@test2
@test1
def love():
print('跟妹子深入畅谈人生和理想。。。。。。5')
love() # 1 3 5 4 2顺序执行,先输出最外层的装饰器结果
结果:
我是扩展1
成功拿到妹子的微信....3
跟妹子深入畅谈人生和理想。。。。。。5
成功约到妹子看电影....4
我是扩展2
五、函数装饰器给类装饰
使用函数装饰器,给类进行装饰,增加新的数据和方法
def decorate(cls):
def func1():
print('我是在装饰器中追加的新方法:func1')
cls.func1 = func1 # 把刚才定义的方法赋值给类
# 新增加的类属性
cls.name = "我是在装饰器中追加的新属性:name"
# 返回时,把追加类新成员的 类 返回
return cls
@decorate
class Demo:
def __init__(self):
print('Demo init')
Demo()
Demo.func1()
print(Demo.name)
# 等于
# res = Demo()
# print(res.name)
输出结果:
Demo init
我是在装饰器中追加的新方法:func1
我是在装饰器中追加的新属性:name