美文网首页
python 闭包 && 装饰器

python 闭包 && 装饰器

作者: 5a031e82bbd5 | 来源:发表于2020-04-03 00:31 被阅读0次
  • 闭包

定义

官方:内部函数对外部函数作用域里变量的引用

个人理解:对于一个内部函数,如果它引用了外部函数的参数和局部变量,且外部函数返回这个内部函数,那么我们把这个内部函数成为闭包函数。闭包函数和作用域外部的变量统称为闭包。

用法

举例,如下是一组嵌套函数fun和fun1

def fun():  #外部函数
    print("This is fun")
    def fun1():    #内部函数
        print("This is fun1")

当我们运行fun()时,可以得到:

This is fun

当我们运行fun1()时,可以得到:

Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'fun1' is not defined

说明内部函数不能直接被调用,func1 是建立在外部函数运行中才能调用。这里我们还需要去理解函数内部作用域的生命周期,只有执行期间才有效。如下:

>>>fun()   #外部函数调用,内部函数创建
>>>fun1()  #无法直接调用,创建在fun()中

这样连续执行命令,我们也无法调用fun1,因为fun()中的函数只有执行期间有效。

为此,我们要调用fun1,可以让fun外部函数返回fun1:

def fun():
    print("This is fun")
    def fun1():
        print("This is fun1")
    return fun1
  
  test = fun()  #fun1
  

这里test就为fun()返回的内部函数fun1;若要调用fun1这个函数,直接使用test()。

此外,可以让内部函数引用外部函数作用域中的变量,使这个变量保存下来,不会失效。如下变量num存在于test()中,相当于私有化了变量,完成了数据封装。

def fun():
    num = 1
    print("This is fun")
    def fun1():
        print(num)
    return fun1
  
>>>test = fun()
>>>test()
This is fun
1

此外,py3之后,新增了nonlocal关键词,可以使内部函数修改外部函数的变量:

def createCounter():
    n=0
    def counter():
        nonlocal n
        n = 2
        print(n)
    counter()
    print(n)

def createCounter2():
    n=0
    def counter():
        n = 2
        print(n)
    counter()
    print(n)
>>>createCounter()
2
2
>>>createCounter2()
2
0

注意:

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

有这样一个例子:

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

全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。所以我们需要另外创建一个函数;

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()
    return fs
  • 装饰器

装饰器函数的标志是:@

装饰器是基于闭包

装饰器的作用是,不影响原函数功能,添加新的功能。他是使函数执行之前先执行装饰器的内容。如下

def log(fun):
    def f():
        print("log装饰器之后调用Toprint函数")
        # return fun    #返回的是原函数这个对象
        return fun()  # 返回的是原函数的调用
    return f

@log
def Toprint():
    print("This is Toprint")


>>>Toprint()
log装饰器之后调用Toprint函数
This is Toprint

他的相当于log(Toprint)(),流程是log(Toprint)() --> return f --> f() --> print("log装饰器之后调用Toprint函数") --> return fun() --> print("This is Toprint")

即接收被装饰器的函数作为参数,并进行调用一次,(如果不调用,返回的只是f函数对象),即执行f(),打印,并执行原函数;

装饰器函数带参

我们不能直接在装饰器函数中传入参数和函数两个参数,需要另外创建一个函数,将参数和原函数分别传入,且在内部接收函数,外部接收参数。

def log(tcp_type):
    def func(b_fun):
        def fun():
            if tcp_type == 'get':
                print('getget')
            if tcp_type == 'post':
                print('postpost')
            return b_fun()
        return fun  # 返回的是原函数的调用
    return func

@log(tcp_type='get')
def get():
    print("This is get")

@log(tcp_type='post')
def post():
    print("This is post")

他的相当于log(tcp_type='get')()(),流程是先调用装饰器函数,返回func函数并调用,返回fun函数并调用,判断tcp_type,打印,调用原函数。

同时支持装饰器带参或者不带参

即:支持:

@log
def f():
    pass

又支持:

@log('execute')
def f():
    pass

我们可以在装饰器函数中写一个默认变量,来进行判断;

def log(tcp_type=None):
    def func(b_fun):
        def fun():
            if tcp_type == 'get':
                print('getget')
            if tcp_type == 'post':
                print('postpost')
            return b_fun()
        return fun  # 返回的是原函数的调用
    return func

@log()
def notcp():
    print("notcp")

@log(tcp_type='get')
def get():
    print("This is get")

@log(tcp_type='post')
def post():
    print("This is post")
>>>notcp()
notcp

被装饰函数带参

被装饰函数的参数可以传入装饰函数的最内部函数中进行操作

def log(func):
    def f(x,y):
        x +=3
        y +=4
        return func(x,y)
    return f

@log
def fun(a,b):
    print(a+b)
>>>fun(3,4)
14

当我们内部函数可以接受任何参数调用时,可以这样写:def fun(*args, **kw)

def metric(fn):
    def f(*args, **kw):
        print('This is %s ' % (fn.__name__))
        return fn(*args, **kw)
    return f

@metric
def fast(x, y):
    print(x + y)

@metric
def slow(x, y, z):
    print(x * y * z)

f = fast(11, 22)
s = slow(11, 22, 33)

相关文章

  • Python的自定义超时机制——装饰器的妙用

    装饰器 关于装饰器的入门,可以参考这篇文章:12步轻松搞定python装饰器简单来说,装饰器其实就是一个闭包(闭包...

  • Python装饰器-专题笔记

    学会装饰器,Python更进阶 函数作用域到闭包到装饰器讲解,及闭包和装饰器的运用。 [√] 慕课网Meshare...

  • [python] 装饰器学习

    很多python的代码都带有装饰器=。=现在不学以后也要学学一下装饰器 闭包 在学装饰器之前先看看python的闭...

  • Python 2 - 高级用法 - 装饰器

    Python 2 - 高级用法 - 装饰器 一谈到 装饰器,就离不开闭包 闭包 闭包就是能够读取其他函数内部变量的...

  • Python装饰器——初识

    上次讲了Python的闭包,今天来讲一下闭包的应用——装饰器 1. 装饰器是什么 什么叫装饰器?顾名思义,它是一个...

  • python装饰器

    装饰器简述 要理解装饰器需要知道Python高阶函数和python闭包,Python高阶函数可以接受函数作为参数,...

  • python之理解闭包和装饰器

    python之理解闭包和装饰器 1、闭包函数 1.1 python中函数都是对象 结果: 上面定义一个shut函数...

  • 2020-012 python闭包与装饰器

    python闭包与装饰器 闭包 函数和对其周围状态(lexical environment,词法环境)的引用捆绑在...

  • 让Python的装饰器不再难理解

    注意: 如果对闭包不了解的同学请移步到这里先,因为装饰器要通过闭包来实现 前言 刚开始学Python的时候,装饰器...

  • Python 装饰器的诞生过程

    Python中的装饰器是通过利用了函数特性的闭包实现的,所以在讲装饰器之前,我们需要先了解函数特性,以及闭包是怎么...

网友评论

      本文标题:python 闭包 && 装饰器

      本文链接:https://www.haomeiwen.com/subject/dxwqphtx.html