Fluent Python 3函数 3函数装饰器和闭包

目录

 

1.装饰器的两个特性

2.Python在被装饰函数定义完之后立即执行装饰器函数

3 变量作用域

4 闭包(嵌套函数)

5 nonlocal 声明

6 一个简单的计时装饰器

7 标准库中的装饰器

8 叠放装饰器

9 参数化的注册装饰器

10 参数化计时装饰器


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() / 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值