python doc中的本地/全局/自由变量定义:
如果名称绑定在块中,则它是该块的局部变量,除非声明为非本地.如果名称在模块级别绑定,则它是全局变量.(模块代码块的变量是局部的和全局的.)如果在代码块中使用了变量但在那里没有定义,则它是一个自由变量.
>>> x = 0
>>> def foo():
... print(x)
... print(locals())
...
>>> foo()
0
{}
Run Code Online (Sandbox Code Playgroud)
>>> def bar():
... x = 1
... def foo():
... print(x)
... print(locals())
... foo()
...
>>> bar()
1
{'x':1}
Run Code Online (Sandbox Code Playgroud)
自由变量locals()在函数块中调用时返回,但不在类块中调用.
In Code 1,x是一个全局变量,它已被使用但未定义foo().
然而,它不是一个自由变量,因为它不是由它返回的locals().
我认为这不是医生所说的.是否有自由变量的技术定义?
nal*_*ply 39
例如:
x在代码1中不是免费的,因为它是一个全局变量.xbar()在代码2中不是免费的,因为它是一个绑定变量.x是免费的foo().由于闭包,Python做出了这种区分.自由变量未在当前环境中定义,即局部变量的集合,也不是全局变量!因此必须在别处定义.这就是闭包的概念.在代码2中,foo()关闭x定义于bar().Python使用词法范围.这意味着,解释器只需查看代码即可确定范围.
例如:x被称为变量in foo(),因为foo()被包围bar(),并被x绑定bar().
全局范围由Python专门处理.可以将全局范围视为最外层的范围,但由于性能(我认为),这不是完成的.因此,不可能x是自由的和全球的.
生活并非如此简单.存在自由的全局变量.Python文档(执行模型)说:
全局语句与同一块中的名称绑定操作具有相同的范围.如果自由变量的最近封闭范围包含全局语句,则将自由变量视为全局变量.
>>> x = 42
>>> def foo():
... global x
... def baz():
... print(x)
... print(locals())
... baz()
...
>>> foo()
42
{}
Run Code Online (Sandbox Code Playgroud)
我自己也不知道.我们都在这里学习.
据我了解,文档对自由变量确实有点含糊不清。有免费的全局变量被视为纯全局和词法约束自由变量。Eli Bendersky 在关于符号表的博客文章中很好地总结了它:
不幸的是,Python 的核心中有一个速记,最初可能会让读者混淆“自由”变量的确切构成。幸运的是,这是一个非常轻微的混乱,很容易整理。执行模型参考说:
如果一个变量在代码块中使用但未在那里定义,则它是一个自由变量。
这与正式的定义是一致的。然而,在源代码中,“free”实际上用作“词法绑定的自由变量”的简写(即在封闭范围内找到,“global”用于指代所有剩余的自由变量变量。因此,在阅读 CPython 源代码时,重要的是要记住,完整的自由变量集包括专门标记为“自由”的变量以及标记为“全局”的变量。
因此,为了避免混淆,当我想将 CPython 中实际处理的变量称为自由变量时,我会说“词法绑定”。
(强调我的)
使用这种速记的原因可能是因为当您拥有全局自由变量时,发出的字节码实际上没有任何变化。如果global变量是“自由”的,或者不是“自由”,则不会改变LOAD_GLOBAL在这两种情况下都将使用该名称的查找这一事实。所以全局自由变量并不是那么特别。
另一方面,词法绑定的变量被特殊对待并被封闭在cell对象中,对象是词法绑定的自由变量的存储空间,位于__closure__给定函数的属性中。LOAD_DEREF为这些创建了一个特殊指令,用于检查存在自由变量的单元格。该LOAD_DEREF指令的描述是:
LOAD_DEREF(i)加载包含在单元格槽 i 中的单元格和自由变量存储
因此,在 Python 中,自由变量仅在具有状态的对象的定义在词法上(即静态地)嵌套在具有状态的对象的另一个定义中的情况下作为概念有所不同。
| 归档时间: |
|
| 查看次数: |
11302 次 |
| 最近记录: |