python装饰器

闭包

简介:当一个函数返回了一个函数后,其内部的局部变量还被新函数引用

  1. 闭包返回的函数不能引用任何循环变量或者后续,会发生变化的变量,如下示例。
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()

输出内容:

>>> f1()
9
>>> f2()
9
>>> f3()
9

大家认为可能的输出为1,4,9,实际并不是,闭包返回的函数并没有立刻执行,而是等全部都返回了才执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。

  1. 若非要引用循环变量,可以修改函数,用一个变量绑定i值,这样就得到了想要的返回结果
    (返回函数不要引用任何循环变量,或者后续会发生变化的变量)
def count():
    fs = []
    for i in range(1, 4):
        def f(j = i):
             return j * j
        fs.append(f)
    return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())

执行结果

1
4
9

装饰器 = 高阶函数 + 函数嵌套 + 闭包

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

  1. 装饰器通常把函数替换成另一个函数

  2. 装饰器在加载模块是立即执行

registry = []   #创建列表用于存储被装饰的函数引用

def register(func):
    print('running register(%s' % func.__name__)
    registry.append(func)
    return func

@register #被装饰的函数f1()将作为装饰器函数的func传入
def f1():
    print('running f1()')

@register #加上装饰器相当于执行了f2 = register(f2)
def f2(): 
    print('running f2()')

def f3():
    print('running f3()')
    
def main():
    print('running main')
    print('registry-', registry)
    f1()
    f2()
    f3()

main()

执行结果

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

f1()和f2()被装饰器修饰,在main()没被调用前就执行了,并且返回该函数的引用。

为什么使用装饰器

首先看一个简单的求素数的例子,不用装饰器的代码如下:

#求素数
def is_prime(num):
    if num == 2 or num == 3:
        return True
    if num % 2 == 0 or num % 3 == 0:
        return False
    for i in range(5, int(math.sqrt(num)) + 1, 6):
        if num % i == 0 or num % (i + 2) == 0:
            return False
    return True

def primes(maxnum):
    total = 0
    t1 = time.time()
    for i in range(2, 1000):
        if is_prime(i):
            print(i)
    t2 = time.time()
    print(t2 - t1)

上述代码求出了2到1000的素数,并且还输出了运行代码所需时间。这里的计算时间只能应用在primes这个方法里,如果我们其他方法也想用就要重新定义t1\t2,然后进行计算,无法复用。装饰器就可以做到代码复用。
下面是装饰器写法:

#装饰器计算时间
def display_time(func):
    def wrapper(*args):
        t1 = time.time()
        result = func(*args)
        t2 = time.time()
        print(t2 - t1)
        return result
    return wrapper

@display_time
def primes(maxnum):
    total = 0
    for i in range(2, maxnum):
        if is_prime(i):
            total += 1
    return total

方法display_time表示装饰器的名称,括号里是要运行的函数(也就是被装饰的函数primes),方法wrapper才是运行函数时要运行的内容,*args代表方法primes传的参数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值