python中的闭包和装饰器

it2024-07-26  38

python中的闭包和装饰器

我们要了解装饰器首先就要了解什么是闭包?

闭包:

      这种函数由两个函数的嵌套组成,且称之为外函数和内函数,外函数返回值是内函数的引用,此时就构成了闭包。

def 外层函数(参数): def 内层函数(): print("内层函数执行", 参数) return 内层函数 内层函数的引用 = 外层函数("传入参数") 内层函数的引用() 例: def func(a, b): def line(x): return a * x - b return line line = func(2, 3) print(line(5)) 结果得到 7 在这个案例中,外函数func有接收参数 a=2,b=3,内函数line接收参数x=5,在内函数体中计算了a*x-b 即 2×5-3的值作为返回值,外函数返回内函数的引用,这里的引用指的是内函数line在内存中的起始地址,最终调用内函数line()得到返回值7

内函数中修改外函数的值

        一般在函数结束时,会释放临时变量,但在闭包中,由于外函数的临时变量在内函数中用到,此时外函数会把临时变量与内函数绑定到一起,这样虽然外函数结束了,但调用内函数时依旧能够使用临时变量,即闭包外层的参数可以在内存中进行保留

如果想要在内函数中修改外函数的值,需要使用 nonlocal 关键字声明变量

def func(a, b):     def line(x):         nonlocal a         a = 3         return a * x - b     return line line = func(2, 3) print(line(5))

闭包的主要用途就是装饰器

装饰器:

      外部函数传入被装饰函数名,内部函数返回装饰函数名。

作用:

不修改被调用函数的代码和调用方式,为函数增加一些功能,也就是说对调用的函数进行包装

1、无参数装饰器

import time, random def index(): time.sleep(random.randrange(1, 5)) print("welcome to index page") index() # 根据装饰器的特点,我们不能对index()进行任何修改,而且调用方式也不能变。这时候,我们就可以使用装饰器来完成如上功能。 import time, random def outer(func): # 将index的地址传递给func def inner(): start_time = time.time() func() # fun = index 即func保存了外部index函数的地址 end_time = time.time() print("运行时间为%s"%(end_time - start_time)) return inner # 返回inner的地址 @outer #相当于index = outer(index),也就是返回的是inner的地址,并重新赋值给index def index(): time.sleep(random.randrange(1, 5)) print("welcome to index page") index()

2、有参数的装饰器

import time import random def timmer(func): def wrapper(): start_time = time.time() func() stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return wrapper def auth(func): def deco(): name=input('name: ') password=input('password: ') if name == 'egon' and password == '123': print('login successful') func() #wrapper() else: print('login err') return deco @auth # index = auth(timmer(index)) @timmer # index = timmer(index) def index(): time.sleep(3) print('welecome to index page') index()

补充:多个装饰器装饰一个函数,其执行顺序是从下往上

3、类装饰器

      装饰器不仅可以是函数,还可以是类,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

class Foo(object): def __init__(self, func): self._func = func def __call__(self): print('class decorator runing') self._func() print('class decorator ending') @Foo  # bar = Foo(bar) def bar(): print('bar') bar()  # Foo(bar)() # 结果 # class decorator runing # bar # class decorator ending class Foo(object): def __init__(self): pass def __call__(self, func): def _call(*args, **kw): print('class decorator runing') return func(*args, **kw) return _call class Bar(object): @Foo() def bar(self, test, ids): # bar = Foo()(bar) print('bar') Bar().bar('aa', 'ids')
最新回复(0)