python之闭包和装饰器

闭包

闭包函数必须满足两个条件:1.函数内部定义的函数 2.包含对外部作用域而非全局作用域的引用

如下闭包函数:

def callFunc():
    n = 1
    def show():
        print('show: ', n)
    return show

s = callFunc()
s()

程序在执行时,callFunc 函数返回了内部定义的 show 函数,并且 在 show 函数内部使用了外部函数的变量。

在 show 函数返回时,保存了当前的执行环境,也就是会在 show 函数中使用的外部变量 n 。

因为 n 是一个 callFunc 函数中的局部变量,正常情况下 callFunc 函数执行结束后,n 就会被释放。

但是现在因为 callFunc 函数中返回了 show 函数,show 函数在外部还会再执行,所以程序会将 show 函数所需的执行环境保存下来。

这种形式就是闭包。

装饰器

装饰器 本身也是一个函数 ,作用是为现有存在的函数,在不改变函数的基础上去增加一些功能进行装饰。

装饰器实际上就是一个函数 ,这个函数以闭包的形式定义

在使用这个装饰器函数时,在被装饰的函数的前一行,使用 @装饰器函数名 形式来装饰

import time

def count_time(func):
    def wrapper():      
        start = time.time()
        func()
        end = time.time()
        print('共计执行:%s 秒'%(end - start)) 
    return wrapper

@count_time     
def my_count():
    s = 0
    for i in range(10000001):
        s += i
    print('sum : ', s)

my_count()

这种不改变原有函数功能基础上,对函数进行扩展的形式,称为装饰器。

在执行 @xxx 时 ,实际就是将 原函数传递到闭包中,然后原函数的引用指向闭包返回的装饰过的内部函数的引用。

装饰器的几种形式:

  1. 无参无返回值
 def setFunc(func):
        def wrapper():
            print('Start')
            func()
            print('End')
        return wrapper

    @setFunc
    def show():
        print('show')

    show()

2、无参有返回值

def setFunc(func):
        def wrapper():
            print('Start')
            return func()
        return wrapper

    @setFunc   # show = setFunc(show)
    def show():
        return 100

    print(show() * 100)

3、有参无返回值

def setFunc(func):
        def wrapper(s):
            print('Start')
            func(s)
            print('End')
        return wrapper

    @setFunc   
    def show(s):
        print('Hello %s' % s)

    show('Tom')

4、有参有返回值

def setFunc(func):
        def wrapper(x, y):
            print('Start')
            return func(x, y)
        return  wrapper

    @setFunc
    def myAdd(x, y):
        return  x + y

    print(myAdd(1, 2))

万能装饰器:

根据被装饰函数的定义不同,上面细分了四种形式,那么能否利用学过的技术,实现一种适用于任何形式函数定义的装饰器呢?

答案是肯定的,通过可变参数和关键字参数来接收不同的参数类型。

 def setFunc(func):
        def wrapper(*args, **kwargs):   # 接收不同的参数
            print('wrapper context')
            return func(*args, *kwargs) # 再原样传回给被装饰的函数

        return wrapper

    @setFunc
    def show(name, age):
        print(name,age)

    show('tom',12)

类实现装饰形式:

通过类的定义也可以实现装饰器形式。

在类中通过使用 __init__ 和 __call__方法来实现

class Test(object):
        # 通过初始化方法,将要被装饰的函数传进来并记录下来
        def __init__(self, func):
            self.__func = func
        # 重写 __call__ 方法来实现装饰内容
        def __call__(self, *args, **kwargs):
            print('wrapper context')
            self.__func(*args, **kwargs)


    # 实际通过类的魔法方法call来实现
    @Test  # --> show = Test(show) show由原来引用函数,装饰后变成引用Test装饰类的对象
    def show():
        pass


    show()  # 对象调用方法,实际上是调用魔法方法call,实现了装饰器

类实现的装饰器在装饰函数后,原来的函数引用不在是函数,而是装饰类的对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值