python doc中的本地/全局/自由变量定义:
如果名称绑定在某个块中,则该块是该块的局部变量,除非声明为非本地。如果名称在模块级别绑定,则它是全局变量。 (模块代码块的变量是局部的和全局的。)如果变量在代码块中使用但未在那里定义,则它是自由变量。
>>> x = 0
>>> def foo():
... print(x)
... print(locals())
...
>>> foo()
0
{}
>>> def bar():
... x = 1
... def foo():
... print(x)
... print(locals())
... foo()
...
>>> bar()
1
{'x':1}
{p> 自由变量在功能块中调用时返回locals()
,但不在类块中调用。
在Code 1
中,x
是一个全局变量,它已被使用但未在foo()
中定义。
但是,它不是自由变量,因为它不会被locals()
返回。
我认为这不是医生所说的。是否有自由变量的技术定义?
答案 0 :(得分:37)
例如:
x
在代码1中不是免费的,因为它是全局变量。x
在代码2中的bar()
中不可用,因为它是绑定变量。x
在foo()
中免费。 Python因为闭包而做出这种区分。在当前环境中未定义自由变量,即。即局部变量的集合,也是不全局变量!因此必须在别处定义。这就是闭包的概念。在代码2中,foo()
关闭x
中定义的bar()
。 Python使用词法范围。这意味着,解释器只需查看代码即可确定范围。
例如:x
在foo()
中称为变量,因为foo()
被bar()
括起来,而x
被bar()
绑定}}
全局范围由Python专门处理。可以将全局范围视为最外层的范围,但由于性能(我认为),这不是完成的。因此,x
不可能免费和全球。
生活并非如此简单。存在自由全局变量。 Python文档(执行模型)说:
全局语句与同一块中的名称绑定操作具有相同的范围。如果自由变量的最近封闭范围包含全局语句,则将自由变量视为全局变量。
>>> x = 42
>>> def foo():
... global x
... def baz():
... print(x)
... print(locals())
... baz()
...
>>> foo()
42
{}
我自己也不知道。我们都在这里学习。
答案 1 :(得分:2)
据我所知,文档在自由变量上确实有点含糊不清。有自由全局变量,它们被视为普通全局变量和词汇绑定自由变量。 Eli Bendersky总结了blog post on symbol tables:
不幸的是,在Python的核心中有一个简写,可能最初会让读者误解为什么构成了一个" free"变量。幸运的是,这很容易让人感到困惑。执行模型参考说:
如果变量在代码块中使用但未在其中定义,则它是一个自由变量。
这与formal definition一致。 然而,在源头,"免费"实际上用作"词汇绑定自由变量的简写" (即在封闭范围内找到绑定的变量)," global"用于指代所有剩余的自由变量。因此,在阅读CPython源代码时,重要的是要记住,完整的自由变量集包括标记为" free"的变量,以及标记为" global"的变量。
因此,为了避免混淆,我说" lexically bound"当我想把CPython中实际处理过的变量称为free。
(强调我的)
使用这种速记的原因可能是因为当你有一个全局自由变量时,在发出的字节码中实际上没有任何变化。如果global
变量是免费的'或者,如果在这两种情况下都没有改变该名称的查找将使用LOAD_GLOBAL
这一事实。所以全局自由变量并不是那么特别。
另一方面,词法绑定变量是专门处理的并且包含在cell
个对象中,对象是词法绑定自由变量的存储空间,位于{{ 1}}给定函数的属性。为这些创建了一个特殊的 LOAD_DEREF
指令,用于检查自由变量的单元格。 __closure__
指令的描述是:
LOAD_DEREF
加载单元格的插槽i中包含的单元格和自由变量存储
因此,在Python中,自由变量仅在具有状态的对象的定义在词法上(即静态地)嵌套在具有状态的对象的另一个定义的情况下作为概念产生差异。
答案 2 :(得分:1)
变量只是用于存储值的保留内存位置。这意味着当您创建变量时,您在内存中保留了一些空间。
根据变量的数据类型,解释器分配内存并决定可以存储在保留内存中的内容。因此,通过为变量分配不同的数据类型,可以在这些变量中存储整数,小数或字符。
将值分配给变量
Python变量不需要显式声明来保留内存空间。为变量赋值时,声明会自动发生。等号(=)用于为变量赋值。
答案 3 :(得分:0)
在Python中声明自由变量没有明确的关键字。根据函数的定义及其内部和周围的语句,Python将变量分类为绑定,单元格和自由变量。
以下示例使用函数的代码对象来说明此概念,该代码对象封装了上一段中提到的变量。
def func(arg1, arg2=2):
def inner_func(arg3=arg2):
return arg1, arg3
arg1, arg2 = None
return inner_func
对于' func ':
• arg1 和 arg2 是绑定变量
• arg1 是一个单元格变量,因为它是' inner_func 中的自由变量 '
•没有自由变量。
func.__code__.co_varnames
(' arg1',' arg2',' inner_func')
func.__code__.co_cellvars
(' ARG1',)
func.__code__.co_freevars
()
对于' inner_func ':
• arg3 是绑定变量
• arg1 是自由变量
•没有单元格变量
inner_func.__code__.co_varnames
(' ARG3',)
inner_func.__code__.co_freevars
(' ARG1&#39)
inner_func.__code__.co_cellvars
()
答案 4 :(得分:0)
为避免新手误导,Nikhil的以上评论开头为“变量只不过是用于存储值的保留内存位置”。对于Python来说是完全错误的。
在Python中,有“名称”和“值”。值具有类型,而不是名称。内存空间是为值保留的,而不是为名称保留的。例如,我们可以让x = 1,然后在代码中后面跟着x =“字符串”,然后跟着x = [3,9.1]。在这些分配过程中,名称x首先指向一个整数,然后指向一个字符串,最后指向一个列表。完成分配后,分配左侧的名称将指向分配右侧的值。值可以是不可更改的(不可变)或可更改的(可变)。整数,字符串,元组等是不可变的;列表等是可变的。由于整数是不可变的,因此当有两个这样的语句时:
x = 4
x = x +1
第二条语句使x指向一个新值5,它没有将x指向的内存位置中的值从4更改为5!
这与说C语言的模式完全不同!