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

代码逐星人
• 阅读 3898

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__)
# 输出:(<cell at 0x7fc50f45afd8: function object at 0x7fc50f4168c0>, <cell at 0x7fc50f45aec0: str object at 0x7fc50c065fc0>)

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: 你问题咋恁些?我先吃个饭,下次有空再聊哈!

点赞
收藏
评论区
推荐文章
半臻 半臻
4年前
Python基础5——装饰器
13、装饰器其本质:在不需要做任何代码变动的前提下,增加额外的功能。装饰器返回的是一个函数对象。相当于把函数作为参数传递进去,然后对函数进行装饰其本质就是一个闭包作用:1.给原来的函数增加额外的功能2.把原来的函数作为参数传递进去13.1基本用法标准版的装饰器pythondefwrapper(func):func为原来的函数名defin
Dax Dax
4年前
JS核心原理理解闭包
前置概念在正式看闭包之前,我们先来学习一下前置知识,那就是JS中的作用域,我们知道,在ES5之中,作用域分为两种:全局作用域和函数作用域,随着ES6的到来,新增了块级作用域,想更好的理解闭包,那么搞清楚作用域是首要条件全局作用域我们知道,对于变量而言,我们一般会分成两类:全局变量和局部变量,一般定义在最外围环境的为全局变量,定义在函数当中的为局部变量,在we
Karen110 Karen110
3年前
一篇文章带你了解JavaScript作用域
在JavaScript中,对象和函数也是变量。在JavaScript中,作用域是你可以访问的变量、对象和函数的集合。JavaScript有函数作用域:这个作用域在函数内变化。一、本地JavaScript变量一个变量声明在JavaScript函数内部,成为函数的局部变量。局部变量有局部作用域:它们只能在函数中访问。JS://codeherecann
Irene181 Irene181
4年前
恶补了 Python 装饰器的六种写法,你随便问~
大家好,我是明哥。今天给大家分享一下关于装饰器的知识点,内容非常干,全程高能,认真吸收看完,一定会对装饰器有更深的理解。Hello,装饰器装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰
Jacquelyn38 Jacquelyn38
4年前
你不可不知的JS面试题(第三期)
1、什么是闭包?如图所示,闭包就是一个定义在函数内部的函数,其作用是将函数内部和函数外部连接起来。大家知道,作用域的问题,就是在函数内部定义的变量称为局部变量,外部取不到值。下面我们通过代码来更加详细地看一下:function A()       let x  1;       return function B()           c
菜园前端 菜园前端
2年前
一篇文章教会你什么是闭包
原文链接:什么是闭包?闭包的概念并不复杂,但是它的定义比较绕(就像平时经常用到它,却又说不出来是什么)。可以在一个作用域中调用函数的内部函数并访问到该函数中的作用域的成员,这就是闭包。给一个建议,网上闭包的概念可以搜出来一大堆,但是你真的了解它吗?你有去调
Bill78 Bill78
4年前
Python 中的闭包
闭包定义:如果在一个内部函数里,对在外部作用于(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包Python中的闭包原文出处:田小计划(http://www.cnblogs.com/wilber2013/p/4658894.html)闭包(closure)是函数式编程的重要的语法结构
Stella981 Stella981
3年前
JavaScript易错知识点整理
前言本文是我学习JavaScript过程中收集与整理的一些易错知识点,将分别从变量作用域,类型比较,this指向,函数参数,闭包问题及对象拷贝与赋值这6个方面进行由浅入深的介绍和讲解,其中也涉及了一些ES6的知识点。JavaScript知识点1.变量作用域vara1;functio
Stella981 Stella981
3年前
Python 装饰器(Decorator)
Python 装饰器(Decorator)装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。下面就一步步看看Python中的装饰器。装饰器本身是一个Python函数,他可以让其他函数在不需要做任何代码变动
Stella981 Stella981
3年前
Python装饰器、内置函数之金兰契友
装饰器:装饰器的实质就是一个闭包,而闭包又是嵌套函数的一种。所以也可以理解装饰器是一种特殊的函数。因为程序一般都遵守开放封闭原则,软件在设计初期不可能把所有情况都想到,所以一般软件都支持功能上的扩展,而对源代码的修改是封闭的。开放封闭原则主要体现在两个方面:对功能扩展开放:意味着有新的需求或变化时,可以对现有代码进行扩展,以适
Stella981 Stella981
3年前
Python装饰器用法实例总结
一、装饰器是什么python的装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。简单的说装饰器就是一个用来返回函数的函数。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离