目录
1.装饰器的两个特性
装饰器是可调用的对象, 其参数是另一个函数(被装饰的函数) 。 装饰器可能会处理被装饰的函数, 然后把它返回, 或者将其替换成另一个函数或可调用对象。
装饰器的一大特性是, 能把被装饰的函数替换成其他函数。 第二个特性是, 装饰器在加载模块时立即执行。
2.Python在被装饰函数定义完之后立即执行装饰器函数
函数装饰器在导入模块时立即执行, 而被装饰的函数只在明确调用时运行。 这突出了导入时和运行时之间的区别。
>>> PLUGINS = dict()
>>> def plugin_register(func):
print('Decorator function plugin_register is running')
PLUGINS[func.__name__] = func
return func
>>> @plugin_register
def one_plugin(name):
print(f"Hello,{name}")
Decorator function plugin_register is running # Python在被装饰函数定义完之后立即执行装饰器函数
>>> one_plugin('zzz')
Hello,zzz # 被装饰的函数只在明确调用时运行
上一篇中,手动创建折扣函数的列表:
#创建包含全部折扣函数的列表
discount_list = [discount1,discount2,discount3]
这里可以运用装饰器来添加折扣函数
discount_list = []
def register(func):
discount_list.append(func)
return func
@register
def discount1(order):
return order.total() * .05 if order.customer.fidelity >= 1000 else 0
如果要临时禁用某个折扣函数,只需要注释掉 @register 即可。
促销折扣策略可以在其他模块中定义, 在系统中的任何地方都行,只要使用 @promotion 装饰即可。
装饰器会定义一个内部函数来替换掉被装饰函数,内部函数要靠闭包来正确运作,为了理解闭包,需要先了解Python的变量工作域
3 变量作用域
Python 不要求声明变量, 但是假定在函数定义体中赋值的变量是局部变量。
示例说明:
>>> a = 10
>>> def f1():
print(a)
>>> def f2():
a = 1
print(a)
>>> def f3():
a += 1
print(a)
>>> f1()
10
>>> f2()
1
>>> f3()
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
f3()
File "<pyshell#8>", line 2, in f3
a += 1
UnboundLocalError: local variable 'a' referenced before assignment
上面代码中,函数 f1 中 a 是全局变量,因为函数 f2 和 f3 对 a 进行了赋值, a 是局部变量,但是函数 f3 中 a 没有值,所以报错了。
可以用 global 语句声明为全局变量
global
语句是作用于整个当前代码块的声明。 它意味着所列出的标识符将被解读为全局变量。
对 f3 进行修改:
>>> def f3():
global a
a += 1
print(a)
>>> f3()
11
4 闭包(嵌套函数)
闭包指延伸了作用域的函数, 其中包含函数定义体中引用、 但是不在定义体中定义的非全局变量。 函数能访问定义体之外定义的非全局变量。
假如要实现一个计算不断增加的系列值的均值的功能
用类实现:
>>> class Average:
def __init__(self):
self.ls = []
def avg(self,n):
self.ls.append(n)
return sum(self.ls)/len(self.ls)
>>> a = Average()
>>> a.avg(10)
10.0
>>> a.avg(20)
15.0
用嵌套函数实现:
>>> def average():
ls = []
def avg(n):
ls.append(n)
return sum(ls)/len(ls)
return avg
>>> a = average()
>>> a(10)
10.0
>>> a(20)
15.0
调用 average() 时,返回一个 avg 函数对象。
每次调用 avg 时,它会把参数添加到系列值中, 然后计算当前平均值。
上面两个实例,一个用类实现,一个用嵌套函数实现,它们有共通之处: 调用 Averager() /