当前位置:首页 » 《随便一记》 » 正文

python -闲谈闭包函数与有参无参装饰器,你掌握了吗_m0_51734025的博客

16 人参与  2022年05月02日 14:16  分类 : 《随便一记》  评论

点击全文阅读


一、什么是闭包函数?

在听了Egon老师的讲解后我有了一些见解来跟xdm分享:

闭包函数=名字空间与作用域+函数嵌套+函数对象
‘闭'函数指的该函数是内嵌函数
‘包’函数指的该函数包含对外层函数作用域名字的引用(不是对全局作用域)
注意:内部函数包含对外部作用域而非全局作用域的引用

来为大家举个例子:

x=100
def f1():
    x=1
    def f2():
        print(x)
    return f2


# 可以理解为f2就是被f1包起来的函数,它的内容(如x)是外层函数f1(x=1)所提供而非全局的作用域(x-100)所提供

f=f1()# ==》f=f1的return=》f=f2==》得到的是f2的内存地址
print(f)# ==><function f1.<locals>.f2 at 0x0000022DA470D3A0>
f()#==》f2()==>1

二、无参装饰器

首先大家要明白装饰器就是闭包函数的一种应用场景

那xdm知道-为何要用装饰器吗?

根据开放封闭原则:对修改封闭,对扩展开放

有时大家在做项目时,你写好了一个功能,当你想要为这个功能添加或修改一些功能时,如果不用装饰器,你可能要在原来的功能代码上进行修改,要是每次都要在原来的代码上进行修改,大家会不会觉得太累了呢?特别是你要在别人写的功能代码上进行修改时。而装饰器遵循的开放封闭原则很好的避免了这个问题。

什么是装饰器?

装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。

强调装饰器的原则:

1 不修改被装饰对象的源代码

2 不修改被装饰对象的调用方式

装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

首先我来跟大家列下无参装饰器的模板:

# 无参装饰器模板

'''def 无参装饰器(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return wrapper
    

@无参装饰器
def 被装饰函数():
    ...
'''

下面我们来用无参装饰器的模板来进行一个小的案例:

import time
def timmer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print(stop - start)
        return res

    return wrapper
# 上面者段代码的功能就是计算传进来的函数func运行所需的时间

# 当运行到@装饰器时,不会去运行装饰器下面的函数,调用的是装饰器的函数功能
@timmer#==>index=tmmer(index)
def index(x,y):
     time.sleep(2)
     print('index %s %s'%(x,y))
     return x+y

index(2,3)
# 输出结果为:
# index 2 3
# 2.006439685821533

这就是套用的无参装饰器的模板,但大家想必也很疑惑和好奇,它的原理是什么,下面我将不用装饰器,来实现上面一样的功能和输出结果

def index(x,y):
    time.sleep(2)
    print('index %s %s'%(x,y))
    return x+y

def outter(func):
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print(stop-start)
        return res
    return wrapper

index=outter(index)
# 将index函数作为参数传入outter(func)
# ==》将outter的返回值传给变量index(注意区分,第一个index和第二个index)
# ==》index=wrapper==》index指向的是wrapper的内存地址而非index函数的内存地址

index(2,3)# ==》其实运行的是wrapper(2,3)
# start=time.time() 记录运行func()开始前的时间
# res=func(*args,**kwargs)==>res=index(2,3)==>index是传进来的参数,(2,3)是wrapper(2,3)的参数
# stop=time.time() 记录func()结束后的时间
# print(stop-start)打印时间差即函数运行的时间
# return res 返回调用index()return的结果 ,若没有return 则默认为None

print('====>',index(2,5))

想必大家应该也明白了其中的原理,有参的装饰器运行的原理也和上面的无参装饰器的原理差不多。当有多个装饰器装饰一个函数时,从最下面的装饰器开始调用

def outter1(func1): #func1=wrapper2的内存地址
    print('加载了outter1')
    def wrapper1(*args,**kwargs):
        print('执行了wrapper1')
        res1=func1(*args,**kwargs)
        return res1
    return wrapper1

def outter2(func2): #func2=wrapper3的内存地址
    print('加载了outter2')
    def wrapper2(*args,**kwargs):
        print('执行了wrapper2')
        res2=func2(*args,**kwargs)
        return res2
    return wrapper2

def outter3(func3): # func3=最原始的那个index的内存地址
    print('加载了outter3')
    def wrapper3(*args,**kwargs):
        print('执行了wrapper3')
        res3=func3(*args,**kwargs)
        return res3
    return wrapper3



@outter1 # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址
@outter2 # outter2(wrapper3的内存地址)======>wrapper2的内存地址
@outter3 # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址
def index():
    print('from index')

print('======================================================')
index()

# 输出结过如下:
’‘’
加载了outter3
加载了outter2
加载了outter1
======================================================
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
‘’‘

三、有参装饰器

有参装饰器模板
'''def 有参装饰器(参数):
    def outter(func):
        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)
            return res
        return wrapper
    return outter

@有参装饰器(参数)
def 被装饰函数():
    ...
'''

原理无非和无参装饰器一样,就不为大家详细介绍啦,有兴趣的兄弟可以课下自己套用模板试一下,不会的可以私信我欧,希望大家喜欢,一起进步!要是喜欢的话欢迎大家来关注我欧~有不足的地方欢迎大家指出,会继续为xdm更新的


点击全文阅读


本文链接:http://zhangshiyu.com/post/39337.html

装饰  函数  内存  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1