Python 函数装饰器和闭包

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 25.0px Helvetica }

装饰器基础知识

  装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。 装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用对象。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

假如有个名为 decorate 的装饰器:

@decorate
def target():
    pprint(‘running target()‘)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

上述代码的效果与下述写法一样:

def target():
    print(‘running target()‘)

target = decorate(target)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

两种写法的最终结果一样:上述两个代码片段执行完毕后得到的target 不一定是原来那个 target 函数,而是 decorate(target) 返回的函数

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

举个?? 装饰器通常把函数替换成另一个函数

 1 def deco(func):
 2     def inner():
 3         print(‘running in inner()‘)
 4     return inner
 5
 6 @deco
 7 def target():
 8     print(‘running in target()‘)
 9
10 target()

以上代码执行的结果为:

running in inner()

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

  严格来说,装饰器只是语法糖。如前所示,装饰器可以像常规的可调用对象那样调用,其参数是另一个函数。有时,这样做更方便,尤其是做元编程(在运行时改变程序的行为)时。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

  综上,装饰器的一大特性是,能把被装饰的函数替换成其他函数。第二个特性是,装饰器在加载模块时立即执行。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 25.0px Helvetica }

Python何时执行装饰器

  装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。这通常是在导入时(即 Python 加载模块时),如 ?? 的registration.py 模块所示。

 1 registry = []
 2
 3 def register(func):
 4     ‘‘‘
 5     :param func:被装饰器的函数
 6     :return: 返回被装饰的函数func
 7     ‘‘‘
 8     print(‘running register(%s)‘ % func)        #获取形参func的的引用
 9     registry.append(func)                       #获取的引用地址放入到类表中
10     return func                                 #执行装饰器的时候返回func
11
12 @register
13 def f1():
14     print(‘running f1()‘)
15
16 @register
17 def f2():
18     print(‘running f2()‘)
19
20 def f3():
21     print(‘running f3()‘)
22
23 def main():
24     print(‘running main()‘)
25     print(‘registry ->‘, registry)
26     f1()
27     f2()
28     f3()
29
30 if __name__ == "__main__":
31     main()

以上代码执行的结果为:

running register(<function f1 at 0x101c7bf28>)
running register(<function f2 at 0x101c83048>)
running main()
registry -> [<function f1 at 0x101c7bf28>, <function f2 at 0x101c83048>]
running f1()
running f2()
running f3()

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

注意,register 在模块中其他函数之前运行(两次)。调用register 时,传给它的参数是被装饰的函数,例如 <function f1 at 0x101c7bf28>。

加载模块后,registry 中有两个被装饰函数的引用:f1 和 f2。这两个函数,以及 f3,只在 main 明确调用它们时才执行。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 25.0px Helvetica }

使用装饰器改进“策略”模式

  使用注册装饰器可以改进的电商促销折扣 ?? 回顾一下,示例 6-6 的主要问题是,定义体中有函数的名称,但是best_promo 用来判断哪个折扣幅度最大的 promos 列表中也有函数名称。这种重复是个问题,因为新增策略函数后可能会忘记把它添加到promos 列表中,导致 best_promo 忽略新策略,而且不报错,为系统引入了不易察觉的缺陷。下面的 ?? 使用注册装饰器解决了这个问题。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

?? promos 列表中的值使用 promotion 装饰器填充

 1 promos = []
 2
 3 def promotion(promo_func):
 4     promos.append(promo_func)
 5     return promo_func
 6
 7 @promotion
 8 def fidelity(order):
 9     """为积分为1000或以上的顾客提供5%折扣"""
10     return order.total() * .05 if order.customer.fidelity >= 1000 else 0
11
12 @promotion
13 def bulk_item(order):
14     """单个商品为20个或以上时提供10%折扣"""
15     discount = 0
16     for item in order.cart:
17         if item.quantity >= 20:
18             discount += item.total() * .1
19     return discount
20
21 @promotion
22 def large_order(order):
23     """订单中的不同商品达到10个或以上时提供7%折扣"""
24     distinct_items = {item.product for item in order.cart}
25     if len(distinct_items) >= 10:
26         return order.total() * .07
27     return 0
28
29 def best_promo(order):
30     """选择可用的最佳折扣"""
31     return max(promo(order) for promo in promos)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

与函数策略给出的方案相比,这个方案有几个优点:

  1. @promotion装饰器突出了被装饰的函数的作用,还便于临时禁用某个促销策略,只需要把装饰器注释掉
  2. 促销折扣策略可以在其他的模块中定义,在系统中的任何地方都行,只要使用@promotion装即可

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 25.0px Helvetica }

变量作用域规则

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica }

时间: 2024-10-18 21:14:13

Python 函数装饰器和闭包的相关文章

python函数装饰器

学习装饰器前提需要了解高阶函数,函数嵌套,函数闭包 python函数装饰器,顾名思义就是装饰函数,为函数添加新功能的的一种方式. 为什么要使用装饰器呢? 因为函数在运行时,如果不使用装饰器对函数进行功能添加,需要修改函数源代码,这样修改无疑会增加程序的冗余和复杂性,也不便于程序员对其进行修改.使用装饰器,可以在不改变函数源代码和调用方式的前提下,使用语法糖@装饰器,对函数功能进行添加. 装饰器本质上就是一个函数. 我们使用一个简单的例子来实现: import time #这是一个装饰器函数名为t

Python 函数装饰器入门

原文链接: --> A guide to Python's function decorators Python功能强劲,语法表现力强,尤其装饰器深深的吸引着我.在设计模式中,装饰器可以在不使用子类的情况下,动态的改变函数,方法以及类的功能.这个功能非常有用,特别在你想扩展函数的功能同时又不想改变原有的函数.的确,我们任意的实现装饰器设计模式,但是,python通过提供简单的语法和特性让装饰器的实现变的如此简单. 在本文中,我将用一组例子来深入浅入python 函数装饰器的功能,所有的例子都是在

函数装饰器和闭包(四)

上一章:函数装饰器和闭包(三) 单分派函数 假设我们现在要开发一个函数,这个函数可以传入一个元素,函数要判断元素的类型,再将其打印出来 from collections.abc import MutableSequence, MutableMapping def print_item(item): if isinstance(item, int): print("int:", item) elif isinstance(item, MutableSequence): print(&qu

python—函数装饰器

闭包 如果在一个内部函数(函数里的函数)里,对在外部作用域(但不是在全局作用域,可以理解为外层函数)的变量进行引用,那么内部函数就被认为是闭包. 例如: def outer(): x=10 # 这里x即为外部作用域变量 def inner(): print(x) return inner # inner函数被称为一个闭包 装饰器 写python代码一定要遵循开放封闭原则.即,可扩展功能,对源代码修改是封闭的.装饰是为函数和类指定管理代码的一种方式.装饰器本身的形式是处理其他的可调用对象的可调用的

函数装饰器和闭包(一)

装饰器基础知识 装饰器是可调用的对象,其参数是另一个函数(被装饰的函数),装饰器可能会处理被装饰的函数,然后将它返回,或者将其替换成另一个函数或可调用对象 def deco(func): def inner(): print("running innner()") return inner # <1> @deco def target(): # <2> print("running target()") target() # <3>

python函数装饰器详解

基础:函数装饰器的表现方式 假如你已经定义了一个函数funcA(),在准备定义函数funcB()的时候,如果写成下面的格式: @funcA def funcB():... 表示用函数funcA()装饰函数funcB().当然,也可以认为是funcA包装函数funcB.它等价于: def funcB():... funcB = funcA(funcB) 也就是说,将函数funcB作为函数funcA的参数,funcA会重新返回另一个可调用的对象(比如函数)并赋值给funcB. 所以,funcA要想作

Python函数--装饰器进阶

开放封闭原则 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新功能. 2.对修改是封闭的 为什么要对修改封闭呢? 就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户. 装饰器完美的遵循了这个开放封闭原则. *args,**kwargs def f1(*args,**kwargs):   接

python 函数 装饰器的使用方法

一.装饰器  首先,我们要了解到什么是开放封闭式原则? 软件一旦上线后,对修改源代码是封闭的,对功能的扩张是开放的,所以我们应该遵循开放封闭的原则. 也就是说:我们必须找到一种解决方案,能够在不修改一个功能源代码以及调用方式的前提下,为其加上新功能. 总结:原则如下: 1.不修改源代码 2.不修改调用方式 目的:在遵循1和2原则的基础上扩展新功能. 二.什么是装饰器? 器:指的是工具, 装饰:指的是为被装饰对象添加新功能. 完整的含义:装饰器即在不修改装饰对象源代码与调用方式的前提下,为被装饰器

python函数装饰器的使用

# -*- coding: utf-8 -*- ''' 使用语法糖@来装饰函数,相当于"myfunc = deco(myfunc)" 但发现deco函数只在第一次被调用,且myfunc函数在第一次后又被多调用了一次 ''' def deco(func): print("before myfunc() called.") func() print("after myfunc() called.") return func bool=0 @deco