资讯专栏INFORMATION COLUMN

Python Enclosing作用域、闭包、装饰器话聊上篇

Faremax / 1900人阅读

摘要:作用域闭包装饰器话聊上篇听讲一切都是对象,是吗是的,像函数也是对象。不错嘛这都被你看出来了,那你知道作用域的原则吗我知道是知道可以我就是对那个作用域不是很理解。如果内部函数引用到外层函数作用域的对象,这个内部函数就称为闭包。

Python Enclosing作用域、闭包、装饰器话聊上篇

Jaglawz: 听讲Python一切都是对象,是吗?

Pylego: 是的,像函数也是对象。

Jaglawz: 那么函数也可以有自己的属性了?

Pylego: 当然,像下面这样写是可以的:

def foo():
    print("I am foo")
    
def bar():
    print("I am bar")
    
foo.bar = bar
foo.bar()

Jaglawz: 这都行,那是不是函数也可以像普通对象一样当作参数传递也可以当作对象来返回?

Pylego: 是的,比如下面的用法:

def deco(func):
    string = "I am deco"
    def wrapper():
        print(string)
        func()
    return wrapper
    

def foo():
    print("I am foo")
    
    
foo = deco(foo)
foo()  
"""
输出:
I am deco
Iam foo
"""

Jaglawz: 好吧,当作参数传递和返回我理解了,但是我对wrapper函数的print(string)这个string的查找感到迷惑。

Pylego: 不错嘛!这都被你看出来了,那你知道Python作用域的LEGB原则吗?

Jaglawz: 我知道是知道可以我就是对那个E(Enclosing)作用域不是很理解。

Pylego: 那就对了,你可以在刚才代码的基础上运行下面的代码:

print(foo.__closure__)
# 输出:(, )

Jaglawz: 咦,这两个内存地址是啥家伙?

Pyelgo: 这就是wrapper函数引用的外层函数(就是deco函数啦)的两个变量:string和func啊!

Jaglawz: 也就是说内层函数(在本例中就是wrapper啦)会把外层函数(在本例用就是deco啦)作用域里面的对象放到__closure__属性里,以供自己查找?

Pylego: 是的,但是不是所有外层函数作用域的对象都会放到内层函数的__closure__属性里,仅限自己用到的,这个__closure__就是enclosing作用域啦!

Jaglawz: 原来enclosing作用域是这样的,明白了。

Pyelgo: 如果内部函数引用到外层函数作用域的对象,这个内部函数就称为闭包。

Jaglawz: 原来闭包就是这家伙,很简单嘛!

Jaglawz: 咦,我想到内部函数有一个妙用,你看看是不是这样啊,比如说我想输出一个函数的运行时间又不想去破坏这个函数的代码,是不是可以这样写:

import time


def time_machine(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        print(u"共耗时: %s秒" % (time.time()-start_time))
    return wrapper
    
    
def foo():
    time.sleep(3)
    
    
foo = time_machine(foo)
foo()

Pylego: 你这智商要冲出宇宙的节奏啊!但是Python的开发者早就想到每次foo = time_machine(foo)很麻烦,特地为你准备了语法糖,来接糖:

import time


def time_machine(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        print(u"共耗时: %s秒" % (time.time()-start_time))
    return wrapper
    

@time_machine
def foo():
    time.sleep(3)

"""
也就是说:
@time_machine
def foo():
    pass
相当于: foo = time_machine(foo),这里是重点,这里是重点,这里是重点,以后的谈话能不能理解就看你对这个语句可理解!
"""

foo()

Pylego: time_machine就是装饰器(decorator),名字起得多形象啊,装饰函数嘛!

Jaglawz: 你这么一说,我就觉得装饰器咋这么简单呢!问题是我看到很多人的装饰器还带参数,还有人用类当装饰器,这又是咋回事呢?

Pylego: 你问题咋恁些?我先吃个饭,下次有空再聊哈!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45493.html

相关文章

  • Python Enclosing作用闭包装饰话聊下篇

    摘要:作用域闭包装饰器话聊下篇作用域闭包装饰器的基础篇,请看作用域闭包装饰器话聊上篇我经常看到有人的装饰器是带参数的,这又是咋回事呢这个其实很简单的,你还记得上次我说相当于那么相当于也就是说,返回的是一个装饰器函数,然后再去装饰其他函数。 Python Enclosing作用域、闭包、装饰器话聊下篇 Python Enclosing作用域、闭包、装饰器的基础篇,请看Python Enclos...

    DirtyMind 评论0 收藏0
  • Python Closure

    摘要:在计算机科学中,闭包又称词法闭包或函数闭包,是引用了自由变量的函数。闭包被广泛应用于函数式语言中。运用闭包可以避免对全局变量的使用。将栈顶的元素取出,创建元组,并将该元组进栈。 在计算机科学中,闭包 又称 词法闭包 或 函数闭包,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。闭包被广泛应用于函数式语言中。 从上面这段话中可以看出闭...

    n7then 评论0 收藏0
  • Python中的函数装饰器和闭包

    摘要:变量查找规则在中一个变量的查找顺序是局部环境,闭包,全局,内建闭包引用了自由变量的函数。闭包的作用闭包的最大特点是可以将父函数的变量与内部函数绑定,并返回绑定变量后的函数,此时即便生成闭包的环境父函数已经释放,闭包仍然存在。 导语:本文章记录了本人在学习Python基础之函数篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、掌握装饰器的本质、功...

    caozhijian 评论0 收藏0
  • Python_装饰器和生成器

    摘要:迭代器迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只往前不会往后退。生成器特点保存了一套生成数值的算法。 迭代器 迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只往前不会往后退。 可迭代对象 以直接...

    sugarmo 评论0 收藏0
  • python闭包探究一二

    摘要:在嵌套函数中访问了最外层函数的参数,结果我们是能正常访问闭包我们将上面的最外层的返回值修改为返回嵌套函数的引用一切皆对象根据前面变量生存期例子,按理说调用完的生命周期应该结束了,调用应该失败才对,但是实际却调用成功了。 复习 python引用变量的顺序: 当前作用域局部变量 -> 外层作用域变量 -> 当前模块中的全局变量 -> python内置变量 global:声明一个全局变量 n...

    jzman 评论0 收藏0

发表评论

0条评论

Faremax

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<