Python闭包和装饰器

闭包

闭包的定义:闭包就是能够读取外部函数内的变量的函数

  • 作用1:闭包是将外层函数内的局部变量和外层函数的外部连接起来的一座桥梁
  • 作用2:将外层函数的变量持久地保存在内存中

例子:

def count(i):
    def f(j):
        return i+j
    return f

t1 = count(1)
print(t1(2))

t2 = count(2)
print(t2(2))

可见count的局部变量 i 保存在了内存中

通过传递不同参数,同一个的函数夹带了不同的私货,就实现了不同的功能
闭包和面向接口编程的概念很像,可以把闭包理解成轻量级的接口封装

返回闭包时,返回函数不要引用任何循环变量,或者后续会发生变化的变量

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()

执行f1 f2 f3时结果是9 9 9

虽然局部变量fs保存了下来,但因为内部函数f()没有被绑定到当前变量i,每次执行f的时候调用的是最后i的值也就是3

也就是说,闭包函数会调用最后的外部函数的变量

解决方法:

1.再写一个闭包函数

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f(),返回的是g函数,i的值保存了下来
    return fs

2.使用默认参数

def count():
    fs = []
    for i in range(1, 4):
        def f(x=i):
            return x*x
        fs.append(f)
    return fs

f1, f2, f3 = count()

通过在内部函数 f 的定义中使用 f(x=i) 的方式,实际上创建了一个带有默认参数的内部函数。

当我们调用 count() 函数时,会进入循环并创建多个内部函数。在每次循环中,都会创建一个新的内部函数 f,并将当前的 i 值作为默认参数 x 的值。这样,每个内部函数都会在定义时捕获其对应的 i 值,并将其作为默认参数的默认值。

装饰器

定义:装饰器本质上是一个Python函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。装饰器用于有以下场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

import time

def count_time(func):
    start_time = time.time()
    func()
    end_time = time.time();
    print("time spent is :",end_time-start_time)

def t1():
    time.sleep(1)
    print('this is t1')

def t2():
    time.sleep(2)
    print('this is t2')


if __name__ == '__main__':
    count_time(t1)
    count_time(t2)

运行结果:

this is t1
time spent is : 1.0067329406738281
this is t2
time spent is : 2.000636100769043

使用语法糖@

import time

def count_time(func):
    def inner():
        start_time = time.time()
        func()
        end_time = time.time();
        print("time spent is :",end_time-start_time)
    return inner

@count_time
def t1():
    time.sleep(1)
    print('this is t1')

@count_time
def t2():
    time.sleep(2)
    print('this is t2')


if __name__ == '__main__':
    t1()
    t2()

结果同上,用@count_time时,调用函数t1,t2会先把函数作为参数给count_time,count_time返回inner函数,所以实际调用的是count_time里的inner闭包函数

不同函数有不同个参数时使用*args(元组),**kargs(字典)

import time

def count_time(func):
    def inner(*args,**kargs):
        start_time = time.time()
        print('args :',len(args))
        func(*args,**kargs)
        end_time = time.time();
        print("time spent is :",end_time-start_time)
    return inner

@count_time
def t1(a,b):
    time.sleep(1)
    print('this is t1')

@count_time
def t2(a,b,c):
    time.sleep(2)
    print('this is t2')


if __name__ == '__main__':
    t1(1,1)
    t2(1,2,3)

运行结果:

args : 2
this is t1
time spent is : 1.005439043045044
args : 3
this is t2
time spent is : 2.0108697414398193

类装饰器:

类装饰器中__init__函数接收函数作为参数,用装饰器时调用__call__

import time
 
 
class Decorator:
    def __init__(self, func):
        self.func = func
 
    def defer_time(self,p):
        time.sleep(p)
        print("类中 {0}s 延时...".format(p))
 
    def __call__(self, *args, **kwargs):
        self.defer_time(args[0])
        self.func()
 
 
@Decorator
def f1():
    time.sleep(1)
    print("f1 1s 延时")
 
 
f1(3)

注意:传入f1()的3会传到__call__中

运行结果:

类中 3s 延时...
f1 1s 延时

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值