从python中闭包到装饰器

2021-07-06  本文已影响0人  _icey_

一、闭包

首先要明确自由变量的含义。自由变量是指在函数中使用,但是并非在此函数中被定义的变量。

闭包不同于其他函数是因为,闭包使用了自由变量,并且闭包中的自由变量在脱离了定义该自由变量的上下文后,依然可以被正常使用。

也就是百度百科上讲的闭包是能够读取其他函数内部变量的函数,即函数+函数内部能访问到的变量的总和就是一个闭包

上代码:

def outer(a):
    c = 1  # outer作用域中定义的变量c
    def inner(b):
        print("inner函数传进来的数字是:", b)
        return a + b + c  # inner函数能够读取到a和c的值
    return inner

result = outer(2)
print(result)  # 返回的是inner函数
print("闭包返回结果:", result(3)) # 这里的结果是 1+2+3 的值

在上述代码中inner函数与变量a和c构成一个闭包。


运行结果.png

二、装饰器

python中的装饰器就是对闭包很好的应用。装饰器顾名思义就是可以给已有函数增加其他功能,而不改动函数本身的代码,这样的做法可以让编程的过程变得更加的灵活,查阅python源码也可以看到很多装饰器的使用

装饰器本身是一个闭包,只是将外部函数的变量名变成了一个函数

装饰器的构成:
函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖

装饰器的执行顺序是先执行装饰器里的方法,然后再执行被装饰函数的代码

上代码:

1. 被装饰的函数不带参数:

import time
def timefun(func):
    def inner():
        start = time.time()
        func()
        end = time.time()
        print(func.__name__,"函数运行时间为",end-start)  # 用函数对象的__name__属性,可以得到函数的名字
    return  inner

@timefun
def f():
    time.sleep(2)
    print("我现在被执行了")

f()
运行结果

这个timefun装饰器的作用非常简单,是为被装饰的函数添加程序运行时间的计时功能,此段程序的运行过程是:函数f作为参数被传入到装饰器timefun中,返回inner函数,再进行调用,现在timefun的效果已经加到函数f上面了。

以后再为其他函数添加计时功能,直接使用timefun装饰器即可,不需要重新写一遍计时的代码。

2. 被装饰的函数带返回值:

对于被装饰函数带返回值的情况,则需要在内层函数中使用变量接收,再将其返回出来


被装饰函数带返回值.png

3. 被装饰的函数有参数:

如果被装饰函数中需要参数传递,则需要在内层函数中留接收的位置

import time


def timefun(func):
    def inner(a):
        start = time.time()
        res = func(a)
        end = time.time()
        print(func.__name__,"函数运行时间为",end-start)  # 用函数对象的__name__属性,可以得到函数的名字
        return res
    return inner


@timefun
def f(a):
    time.sleep(2)
    print("我现在被执行了")
    return "我是返回值,我返回了参数{}".format(a)
运行结果

TIPS: 如果按照解包的方式传递参数,调用的时候参数也可以不填,代码如下

import time


def timefun(func):
   def inner(*args,**kwargs):
       start = time.time()
       res = func(args)
       end = time.time()
       print(func.__name__,"函数运行时间为",end-start)  # 用函数对象的__name__属性,可以得到函数的名字
       return res
   return inner


@timefun
def f(a):
   time.sleep(2)
   print("我现在被执行了")
   return "我是返回值,我返回了参数{}".format(a)

4. 装饰器带参数

如果要在装饰器装饰函数的时候向装饰器内部传值的话,则需要定义带参数的装饰器,定义的方式也非常简单,就是将之前的装饰器外层再嵌套一层函数,并且将第二层函数作为返回值返回,代码如下:

import time

def timefun(param):
    print(param)
    def outer(func):
        def inner(*args,**kwargs):
            start = time.time()
            res = func(args)
            end = time.time()
            print(func.__name__,"函数运行时间为",end-start)  # 用函数对象的__name__属性,可以得到函数的名字
            return res
        return inner

    return outer

@timefun("f函数中使用的")
def f(a):
    time.sleep(2)
    print("我现在被执行了")
    return "我是返回值,我返回了参数{}".format(a)

print(f())
print("---------------------分割线------------------------")
@timefun("g函数中使用的")
def g(a):
    time.sleep(2)
    print("我现在被执行了")
    return "我是返回值,我返回了参数{}".format(a)
print(g())
运行结果.png
上一篇下一篇

猜你喜欢

热点阅读