Python 变量作用域 LEGB (下)—— Enclosing function locals

上篇:Python 变量作用域 LEGB (上)—— Local,Global,Builtin

https://www.cnblogs.com/yvivid/p/python_LEGB_1.html

下篇 没想到 拖这么久,距离上篇完成 都一年多了。

一、闭包常规形态下的 locals作用域

 典型的闭包 如下:

def outer(x = 3):
    def inner(y):
        print("yvivid‘s test")
        print("Locals =", locals())
        print("Globals =", globals())        return x+y
    return inner

运行结果如下:

>>> Enclose_Func = outer(73)
>>> Enclose_Func(10)
yvivid‘s testLocals = {‘y‘: 10, ‘x‘: 73}Globals = {‘__name__‘: ‘__main__‘, ‘__doc__‘: None, ‘__package__‘: None, ‘__loader__‘: <class ‘_frozen_importlib.BuiltinImporter‘>,            ‘__spec__‘: None, ‘__annotations__‘: {}, ‘__builtins__‘: <module ‘builtins‘ (built-in)>,            ‘outer‘: <function outer at 0x0000018AFDB0CD90>, ‘Enclose_Func‘: <function outer.<locals>.inner at 0x0000018AFB091EA0>}83

可以看到,在 闭包内查看 locals() 时,可以看到 x 和 y。

为了进一步看,x 和 y 是否变化,yvivid将代码变更为如下:

def outer(x = 3):
    def inner(y):
        print("yvivid‘s test")
        print("Locals =", locals())
        print("Globals =", globals())
        print(id(x), id(y))
        return x + y
    return inner

即,仅增加了 id 的判定。考虑到 python 数字引用机制,使用大于255的数字进行测试。

运行结果如下:

>>> Enclose_Func = outer(500)
>>> Enclose_Func(322)
yvivid‘s test
Locals = {‘y‘: 322, ‘x‘: 500}
Globals = {‘__name__‘: ‘__main__‘, ‘__doc__‘: None, ‘__package__‘: None, ‘__loader__‘: <class ‘_frozen_importlib.BuiltinImporter‘>,            ‘__spec__‘: None, ‘__annotations__‘: {}, ‘__builtins__‘: <module ‘builtins‘ (built-in)>,            ‘outer‘: <function outer at 0x0000021A09E8CD90>, ‘Enclose_Func‘: <function outer.<locals>.inner at 0x0000021A09E86158>}
2310858531312 2310858531600822
>>> Enclose_Func(322)
yvivid‘s test
Locals = {‘y‘: 322, ‘x‘: 500}
Globals = {‘__name__‘: ‘__main__‘, ‘__doc__‘: None, ‘__package__‘: None, ‘__loader__‘: <class ‘_frozen_importlib.BuiltinImporter‘>,            ‘__spec__‘: None, ‘__annotations__‘: {}, ‘__builtins__‘: <module ‘builtins‘ (built-in)>,            ‘outer‘: <function outer at 0x0000021A09E8CD90>, ‘Enclose_Func‘: <function outer.<locals>.inner at 0x0000021A09E86158>}
2310858531312 2310858531920822

可以看到 运行两次,其中 id(y) 是不变更的,而 id(x) 发生了变更,因此 每次 x 是作为形参传入的。而 y 是在 Enclose_Func = outer(500) 时 确定的。

二、闭包特殊形态下的 locals作用域

在 Python 中 部分特殊的 闭包形式。

1、列表推导

>>> [ ‘Locals =‘ + repr(locals()) for i in range(4)]["Locals ={‘i‘: 0, ‘.0‘: <range_iterator object at 0x000002C2563CE330>}",  "Locals ={‘i‘: 1, ‘.0‘: <range_iterator object at 0x000002C2563CE330>}",  "Locals ={‘i‘: 2, ‘.0‘: <range_iterator object at 0x000002C2563CE330>}",  "Locals ={‘i‘: 3, ‘.0‘: <range_iterator object at 0x000002C2563CE330>}"]

>>> print("Globals =", globals())‘Globals =‘, {‘__name__‘: ‘__main__‘, ‘__doc__‘: None, ‘__package__‘: None, ‘__loader__‘: <class ‘_frozen_importlib.BuiltinImporter‘>,  ‘__spec__‘: None, ‘__annotations__‘: {}, ‘__builtins__‘: <module ‘builtins‘ (built-in)>}

>>> iTraceback (most recent call last):File "<pyshell#99>", line 1, in <module>iNameError: name ‘i‘ is not defined

可以看到 在yvivid做的 列表推导测试中,globals() 中 是看不到 列表推导中 变量 i 的。

这个和 for 循环有很大的不同。

2、生成器

yvivid_generator = (‘Locals =‘ + repr(locals()) for i in range(4))

3、集合推导

yvivid_set = {‘Locals =‘ + repr(locals()) for i in range(4)}

-------

A、代码 都基于 Python 3.6 环境。

B、参考书籍 《Python学习手册(第四版)》

【原创文档,引用请声明出处,yvivid】https://www.cnblogs.com/yvivid/p/python_LEGB_2.html

原文地址:https://www.cnblogs.com/yvivid/p/python_LEGB_2.html

时间: 2024-08-29 14:18:08

Python 变量作用域 LEGB (下)—— Enclosing function locals的相关文章

Python 变量作用域 LEGB

回顾 - Decorator 前篇有讲到了, 闭包和装饰器的概念. 闭包就是, 函数内部嵌套函数. 而 装饰器只是闭包的特殊场景而已, 特殊在如果外函数的参数是指向一个, 用来被装饰的函数地址时(不一定是地址哈, 随意就好) , 就有了 "@xxx" 这样的写法, 还是蛮有意思的. 装饰器的作用是 在不改变原函数的代码前提下, 额外给原函数填写新功能. 写法上来看, 还是比较简洁优雅的. 装饰器的通俗写法 # 装饰器的通用写法 def out(func): def inner(*arg

Python变量作用域

Python对于作用域有四种:buildin作用域.全局作用域(模块作用域或文件作用域).高层函数作用域和局部作用域. 其中buildin作用域是Python内建作用域,在Python初始化时建立的: 全局作用域是在文件中直接定义的变量所处的作用域: 高层函数作用域是外层函数中定义的局部变量所处的作用域: 局部作用域是函数内部定义的局部变量所处的作用域: 而在Python语言中变量赋值的位置即是其变量所处的作用域. Python在查找一个变量时首先从局部作用域查起,若未找到则依次查找高层函数作用

python 变量作用域

python能够改变变量作用域的代码段是def(函数).class(类).lamda. if/elif/else.try/except/finally.for/while 并不能涉及变量作用域的更改,也就是说他们的代码块中的变量,在外部也是可以访问的,这点与有{}标注界限的其他类型语言不通.特别注意. 变量搜索路径是:本地变量->全局变量

Python变量作用域(一)

在一个程序中使用变量名时,Python创建.改变或者查找变量名都是在所谓的命名空间中进行的.作用域指的就是命名空间. Python中的变量名在第一次赋值时已经创建,并且必须经过赋值后才能够使用.由于变量名最初没有声明,Python将一个变量名 被赋值的地点关联为一个特定的命名空间.也即是说,在代码中给一个变量赋值的地方决定了这个变量将存在于哪个命名空间,也 就是它可见的范围. 函数除了打包代码之外,还为程序增加了一个额外的命名空间曾:在默认的情况下,一个函数的所有变量名都是与函数的命名空间 相关

39 py函数作用域递归函数 变量作用域局部函数 使用lambda

第十课:函数作用域 // python 中的嵌套函数 在一个函数中再定义一个函数 # 小结 : # 函数作用域:因为:python是动态语言,定义变量的时候是不需要指定变量类型的,这样的话,我们在使用或者定义变量的时候作用域会分不清 # 如果在函数中定义一个变量,而且变量名和该函数上一级的作用域中的变量名相同 # 那么在该函数使用该变量时,就会使用局部变量 # 如果在函数中使用一个变量,但该变量在函数中并没有定义,那么会到该函数上一层的作用域去寻找该变量,如果还没有找到,会继续到上一层作用域去寻

[Python] 命名空间&amp;作用域

Python的类语句不会创建实例 类会创建命名空间,通过对象访问类的属性和方法 类不会创建作用域,对方法和属性的引用必须加以限定(如在方法中必须通过self引用实例的属性) class My1(): my1 = "My1bianliang" def __init__(self): print("My1gouzao") def __del__(self): print("My1xigou") class My2(): def __init__(se

ParisGabriel:Python全栈工程师(0基础到精通)教程 第十五课(函数嵌套、变量作用域)

ParisGabriel 感谢 大家的支持 每天坚持 一天一篇 点个订阅吧  灰常感谢    当个死粉也阔以 Python人工智能从入门到精通 globals()/locals()函数: globals()返回当前全局作用域内变量的字典 locals() 返回当前局部作用域内变量的字典函数变量: 函数名是变量,它在def 语句创建时绑定函数 fa1 = fa 没有括号 绑定函数 fa1 = fa() 返回结果 函数的变量名可以序列交换算法一个函数可以作为另一个函数的实参传递: 例如: def m

python变量和作用域

1.作用域介绍 python中的作用域分4种情况: L:local,局部作用域,即函数中定义的变量: E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的: G:globa,全局变量,就是模块级别定义的变量: B:built-in,系统固定模块里面的变量,比如int, bytearray等. 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB. x = int(2.9) # int

2015/9/19 Python基础(15):变量作用域及生成器

变量作用域标识符的作用域是定义为其声明的可应用范围,或者即是我们所说的变量可见性.也就是,我们可以在程序的那个部分去访问一个制定的标识符.全局变量与局部变量定义在函数内的变量有局部作用域,在一个模块中最高级别的变量有全局作用域.全局变量的一个特征是除非被删除掉,否则它们将存活到脚本运行结束,且对于所有的函数,他们的值都是可以被访问的,然而局部变量,就像它们存放的栈,暂时地存在,仅仅只依赖于定义它们的函数现阶段是否处于活动.当一个函数调用出现时,其局部变量就进入声明它们的作用域.在那一刻,一个新的