如何在python中定义自由变量?

时间:2012-10-16 16:28:24

标签: python

python doc中的本地/全局/自由变量定义:

  

如果名称绑定在某个块中,则该块是该块的局部变量,除非声明为非本地。如果名称在模块级别绑定,则它是全局变量。 (模块代码块的变量是局部的和全局的。)如果变量在代码块中使用但未在那里定义,则它是自由变量


代码1:

>>> x = 0
>>> def foo():
...   print(x)
...   print(locals())
... 
>>> foo()
0
{}

代码2:

>>> def bar():
...   x = 1
...   def foo():
...     print(x)
...     print(locals())
...   foo()
... 
>>> bar()
1
{'x':1}
{p> 自由变量在功能块中调用时返回locals(),但不在类块中调用。


Code 1中,x是一个全局变量,它已被使用但未在foo()中定义。
但是,它不是自由变量,因为它不会被locals()返回。
我认为这不是医生所说的。是否有自由变量的技术定义?

5 个答案:

答案 0 :(得分:37)

自由变量的定义:已使用,但既不全局也不绑定

例如:

  1. x在代码1中不是免费的,因为它是全局变量。
  2. x在代码2中的bar()中不可用,因为它是绑定变量。
  3. xfoo()中免费。
  4. Python因为闭包而做出这种区分。在当前环境中未定义自由变量,即。即局部变量的集合,也是全局变量!因此必须在别处定义。这就是闭包的概念。在代码2中,foo()关闭x中定义的bar()。 Python使用词法范围。这意味着,解释器只需查看代码即可确定范围。

    例如:xfoo()中称为变量,因为foo()bar()括起来,而xbar()绑定}}

    全局范围由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语言的模式完全不同!