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

Posted yvivid

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 test
Locals = {\'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 2310858531600

822
>>> 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 2310858531920
822

可以看到 运行两次,其中 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)>}

>>> i
Traceback (most recent call last):
File "<pyshell#99>", line 1, in <module>
i
NameError: 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

 

以上是关于Python 变量作用域 LEGB (下)—— Enclosing function locals的主要内容,如果未能解决你的问题,请参考以下文章

函数作用域的LEGB顺序

Python 变量作用域 LEGB

LEGB

Python作用域

python3闭包

python中对变量的作用域LEGB闭包装饰器基本理解