接前3篇:
1、学点装饰器(1)
2、学点装饰器(2)
3、闭包学习
1. wraps装饰器
在functools
标准库中,提供有一个wraps
装饰器,那它的用处是什么呢?看一个例子:
def wrapper(func):
def inner_func():
pass
return inner_func
@wrapper
def wrapped():
pass
print(wrapped.__name__)
运行结果:
inner_func
Process finished with exit code 0
1.1 为什么不是返回 func
?
因为上面执行func
和下边的decorator(func)
是等价的,所以上面的func.__name__
是等价于下面的decorator(func).__name__
的,所以名字就是inner_func
。
def wrapper(func):
def inner_func():
pass
return inner_func
def wrapped():
pass
print(wrapper(wrapped).__name__)
1.2 怎么避免?
要避免这种情况的发生的方法是,使用functools.wraps
装饰器,它的作用是将被修饰的函数wrapped
的一些属性值赋值给修饰器函数wrapper
。
from functools import wraps
def wrapper(func):
@wraps(func)
def inner_func():
pass
return inner_func
@wrapper
def wrapped():
pass
print("wraps: {}".format(wrapped.__name__))
运行结果:
wraps: wrapped
Process finished with exit code 0
wraps
其实是一个偏函数partial
对象,源码如下:
def wraps(wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
return partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated)
可以看到wraps
其实是调用了一个函数update_wrapper
,知道原理后,可以在不使用wraps
的情况下改写上面的代码,让wrapped.__name___
打印出wrapped
,代码如下:
from functools import update_wrapper
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
'__annotations__')
def wrapper(func):
def inner_func():
pass
update_wrapper(inner_func, func, assigned=WRAPPER_ASSIGNMENTS)
return inner_func
@wrapper
def wrapped():
pass
print("update_wrapper: {}".format(wrapped.__name__))
运行结果:
update_wrapper: wrapped
Process finished with exit code 0
2. 内置装饰器:property
property
是python内置的一个装饰器,它通常存在于类中,可以将一个函数定义成一个属性,属性的值就是该函数return
的内容。
class StudentInfo(object):
def __init__(self, name):
self.name = name
# self.name = None
@property
def age(self):
print("age info is: {}={}".format(self.name, self._age))
return self._age
@age.setter
def age(self, value):
if not isinstance(value, int):
raise ValueError("年龄必须为数值!")
if not 0 < value < 100:
raise ValueError("年龄范围必须在0-100")
self._age = value
@age.deleter
def age(self):
del self._age
xiaoming = StudentInfo("小明")
# 设置属性
xiaoming.age = 18
# 查询属性
xiaoming.age
# 删除属性
del xiaoming.age
用@property
装饰过的函数,会将一个函数定义成一个属性,属性的值就是该函数return
的内容,同时会将这个函数变成另外一个装饰器,就像后面使用的@age.setter
和@age.deleter
。
-
@age.setter
:使得我们可以使用xiaoming.age = 18
这样的方式直接复制; -
@age.deleter
:使得我们可以使用del xiaoming.age
这样的方式来删除属性;