简体   繁体   English

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

[英]How to define free-variable in python?

The local/global/free variable definitions from python doc : python doc中本地/全局/自由变量定义:

If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal. 如果名称绑定在块中,则它是该块的局部变量 ,除非声明为非本地。 If a name is bound at the module level, it is a global variable . 如果名称在模块级别绑定,则它是全局变量 (The variables of the module code block are local and global.) If a variable is used in a code block but not defined there, it is a free variable . (模块代码块的变量是局部的和全局的。)如果在代码块中使用了变量但在那里没有定义,则它是一个自由变量


Code 1: 代码1:

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

Code 2: 代码2:

>>> def bar():
...   x = 1
...   def foo():
...     print(x)
...     print(locals())
...   foo()
... 
>>> bar()
1
{'x':1}

Free variables are returned by locals() when it is called in function blocks, but not in class blocks. locals()在函数块中调用时返回自由变量 ,但在类块中不调用。


In Code 1 , x is a global variable , and it's used but not defined in foo() . Code 1x是一个全局变量 ,它在foo()使用但未定义。
However it's not a free variable , because it's not returned by locals() . 但是它不是一个自由变量 ,因为它不是由locals()返回的。
I think it's not what the doc said. 我认为这不是医生所说的。 Is there a technical definition for free variable ? 是否有自由变量的技术定义?

Definition of a free variable: Used, but neither global nor bound . 自由变量的定义:已使用,但既不是全局变量也不是绑定变量。

For example: 例如:

  1. x is not free in Code 1, because it's a global variable. x在代码1中不是免费的,因为它是一个全局变量。
  2. x is not free in bar() in Code 2, because it's a bound variable. x在代码2中的bar()中不是空闲的,因为它是一个绑定变量。
  3. x is free in foo() . xfoo()是免费的。

Python makes this distinction because of closures. 由于闭包,Python做出了这种区分。 A free variable is not defined in the current environment, ie collection of local variables, and is also not a global variable! 自由变量未在当前环境中定义,即局部变量的集合, 也不是全局变量! Therefore it must be defined elsewhere. 因此必须在别处定义。 And this is the concept of closures. 这就是闭包的概念。 In Code 2, foo() closes on x defined in bar() . 在代码2中, foo()bar()定义的x关闭。 Python uses lexical scope. Python使用词法范围。 This means, the interpreter is able to determine the scope by just looking at the code. 这意味着,解释器只需查看代码即可确定范围。

For example: x is known as a variable in foo() , because foo() is enclosed by bar() , and x is bound in bar() . 例如: xfoo()被称为变量,因为foo()bar()括起, x绑定在bar()

Global scope is treated specially by Python. 全局范围由Python专门处理。 It would be possible to view the global scope as an outermost scope, but this is not done because of performance (I think). 可以将全局范围视为最外层的范围,但由于性能(我认为),这不是完成的。 Therefore it is not possible that x is both free and global . 因此, x不可能是自由的全局的

Exemption 豁免

Life is not so simple. 生活并非如此简单。 There exist free global variables. 存在自由的全局变量。 Python docs (Execution model) says: Python文档(执行模型)说:

The global statement has the same scope as a name binding operation in the same block. 全局语句与同一块中的名称绑定操作具有相同的范围。 If the nearest enclosing scope for a free variable contains a global statement, the free variable is treated as a global. 如果自由变量的最近封闭范围包含全局语句,则将自由变量视为全局变量。

>>> x = 42
>>> def foo():
...   global x
...   def baz():
...     print(x)
...     print(locals())
...   baz()
... 
>>> foo()
42
{}

I didn't know that myself. 我自己也不知道。 We are all here to learn. 我们都在这里学习。

From what I have understood the documentation is indeed a bit ambiguous on free variables. 根据我的理解,文档确实对自由变量有点模棱两可。 There are free global variables which are treated as plain globals and lexically bound free variables . 有一些自由的全局变量被视为普通全局变量和词法绑定的自由变量 Eli Bendersky sum's it up nicely in a blog post on symbol tables : Eli Bendersky 在符号表博客文章中总结得很好:

Unfortunately, there's a shorthand in the core of Python that may initially confuse readers as to exactly what constitutes a "free" variable. 不幸的是,在Python的核心中有一个简写,可能最初会使读者误解为什么构成“自由”变量。 Fortunately, it's a very slight confusion that's easy to put in order. 幸运的是,这是一个非常轻微的混乱,很容易整理。 The execution model reference says: 执行模型参考说:

If a variable is used in a code block but not defined there, it is a free variable. 如果变量在代码块中使用但未在那里定义,则它是一个自由变量。

This is consistent with the formal definition . 这与正式定义一致。 In the source, however, "free" is actually used as a shorthand for "lexically bound free variable" (ie variables for which a binding has been found in an enclosing scope), with "global" being used to refer to all remaining free variables. 然而,在源中,“free”实际上被用作“词汇绑定自由变量”的简写 (即在封闭范围内找到绑定的变量),“global”用于表示所有剩余的自由变量变量。 So when reading the CPython source code it is important to remember that the full set of free variables includes both the variables tagged specifically as "free", as well as those tagged as "global". 因此,在阅读CPython源代码时,重要的是要记住,完整的自由变量集包括标记为“free”的变量,以及标记为“global”的变量。

Thus, to avoid a confusion I say "lexically bound" when I want to refer to the variables actually treated in CPython as free. 因此,为了避免混淆,当我想将CPython中实际处理的变量称为free时,我说“词法绑定”。

(emphasis mine) (强调我的)

The reason why this shorthand was used is probably because when you have a global free variable there's really no change whatsoever in the bytecode emitted. 使用这种速记的原因可能是因为当你有一个全局自由变量时 ,在发出的字节码中几乎没有任何变化。 If a global variable is 'free' or if it isn't doesn't change the fact that the look-up for that name will use LOAD_GLOBAL in both cases. 如果global变量是“空闲”或者不是,则不会更改在两种情况下该名称的LOAD_GLOBAL都将使用LOAD_GLOBAL So global free variables aren't all that special. 所以全局自由变量并不是那么特别。

On the other hand, lexically bound variables are treated specially and are enclosed in cell objects, the objects are the storage space for lexically bound free variables and are located in the __closure__ attribute for a given function. 另一方面,词法绑定变量被特殊处理并包含在cell对象中,对象是词法绑定自由变量的存储空间,并且位于给定函数的__closure__属性中。 A special LOAD_DEREF instruction is created for these that examines the cells present for the free variables. 为这些创建了一个特殊的LOAD_DEREF指令,用于检查自由变量的单元格。 The description for the LOAD_DEREF instruction is: LOAD_DEREF指令的描述是:

LOAD_DEREF(i)

Loads the cell contained in slot i of the cell and free variable storage 加载单元格的插槽i中包含的单元格和自由变量存储

So in Python free variables only make a difference as a concept in situations where a definition for an object that has state is lexically (ie statically) nested in another definition for an object that has state. 因此,在Python中,自由变量仅在具有状态的对象的定义在词法上(即静态地)嵌套在具有状态的对象的另一个定义的情况下作为概念产生差异。

Variables are nothing but reserved memory locations to store values. 变量只是用于存储值的保留内存位置。 This means that when you create a variable you reserve some space in memory. 这意味着当您创建变量时,您在内存中保留了一些空间。

Based on the data type of a variable, the interpreter allocates memory and decides what can be stored in the reserved memory. 根据变量的数据类型,解释器分配内存并决定可以存储在保留内存中的内容。 Therefore, by assigning different data types to variables, you can store integers, decimals or characters in these variables. 因此,通过为变量分配不同的数据类型,可以在这些变量中存储整数,小数或字符。

Assigning Values to Variables 将值分配给变量

Python variables do not need explicit declaration to reserve memory space. Python变量不需要显式声明来保留内存空间。 The declaration happens automatically when you assign a value to a variable. 为变量赋值时,声明会自动发生。 The equal sign (=) is used to assign values to variables. 等号(=)用于为变量赋值。

There is no explicit keyword to declare a free variable in Python. 在Python中没有明确的关键字来声明自由变量。 Based on the definition of a function and the statements inside and surrounding it, Python will classify variables into bound, cell and free variables. 基于函数的定义及其内部和周围的语句,Python将变量分类为绑定,单元和自由变量。

The following example illustrates this concept using the function's code object which encapsulates the variables mentioned in the previous paragraph. 下面的示例使用函数的代码对象来说明此概念,该代码对象封装了上一段中提到的变量。

def func(arg1, arg2=2):
    def inner_func(arg3=arg2):
        return arg1, arg3
    arg1, arg2 = None
    return inner_func

For ' func ': 对于' func ':

arg1 and arg2 are bound variables arg1arg2绑定变量

arg1 is a cell variable since it is a free variable inside of ' inner_func ' arg1是一个单元格变量,因为它是' inner_func '中的自由变量

• There are no free variables. •没有自由变量。

func.__code__.co_varnames

('arg1', 'arg2', 'inner_func') ('arg1','arg2','inner_func')

func.__code__.co_cellvars

('arg1',) ( 'ARG1',)

func.__code__.co_freevars

() ()

For ' inner_func ': 对于' inner_func ':

arg3 is a bound variable arg3绑定变量

arg1 is a free variable arg1是一个自由变量

• There are no cell variables •没有细胞变量

inner_func.__code__.co_varnames

('arg3',) ( 'ARG3',)

inner_func.__code__.co_freevars

('arg1') ( 'ARG1')

inner_func.__code__.co_cellvars

() ()

Just so that novices don't get mislead, the comment above by Nikhil starting with "Variables are nothing but reserved memory locations to store values." 为了让初学者不会误导,Nikhil上面的评论以“变量开头只是保留存储位置来保存值”。 is completely wrong for Python. 对Python来说是完全错误的。

In Python there are "names" and there are "values". 在Python中有“名称”,还有“值”。 Values have types, not names. 值包含类型,而不是名称。 Memory space is reserved for values, not for names. 内存空间保留用于值,而不是名称。 Eg, we can have x = 1 followed later in the code by x = "a string" followed later by x = [3, 9.1]. 例如,我们可以使用x = 1,然后在代码中跟随x =“a string”,之后是x = [3,9.1]。 Over the course of these assignments the name x first points to an integer, then to a string, and finally to a list. 在这些赋值过程中,名称x首先指向一个整数,然后指向一个字符串,最后指向一个列表。 When an assignment is done, the name on the left side of the assignment is made to point to the value on the right hand side of the assignment. 完成分配后,分配左侧的名称将指向分配右侧的值。 Values can be un-changeable (immutable) or changeable (mutable). 值可以是不可更改的(不可变的)或可更改的(可变的)。 Integers, strings, tuples, etc are immutable; 整数,字符串,元组等是不可变的; lists, etc are mutable. 列表等是可变的。 Since integers are immutable, when there are two statements like this: 由于整数是不可变的,当有两个这样的语句时:

x = 4 x = 4

x = x +1 x = x +1

the second statement makes x point to a new value 5, it is not changing the value in the memory location pointed at by x from 4 to 5! 第二个语句使x指向一个新值5,它不会将x指向的内存位置中的值从4更改为5!

This is a very different model from that of say the C language! 这是一个与C语言完全不同的模型!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM