6. 简单语句

简单语句包含在单一的一个逻辑行中。Several simple statements may occur on a single line separated by semicolons. The syntax for simple statements is:

simple_stmt ::=  expression_stmt
                 | assert_stmt
                 | assignment_stmt
                 | augmented_assignment_stmt
                 | pass_stmt
                 | del_stmt
                 | print_stmt
                 | return_stmt
                 | yield_stmt
                 | raise_stmt
                 | break_stmt
                 | continue_stmt
                 | import_stmt
                 | global_stmt
                 | exec_stmt

6.1. 表达式语句

Expression statements are used (mostly interactively) to compute and write a value, or (usually) to call a procedure (a function that returns no meaningful result; in Python, procedures return the value None). Other uses of expression statements are allowed and occasionally useful. The syntax for an expression statement is:

expression_stmt ::=  expression_list

An expression statement evaluates the expression list (which may be a single expression).

在交互模式下,如果值不是None,它将被内建的repr()函数转换为一个字符串,产生的字符串被写到标准输出(参见print语句) 的一行上。(Expression statements yielding None are not written, so that procedure calls do not cause any output.)

6.2. 赋值语句

赋值语句用于(重新)绑定名称到具体的值以及修改可变对象的属性或元素:

assignment_stmt ::=  (target_list "=")+ (expression_list | yield_expression)
target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" target_list ")"
                     | "[" target_list "]"
                     | attributeref
                     | subscription
                     | slicing

(最后三种符号的定义参见初级操作一节。)

赋值语句计算expression_list(记住,它可以是一个单一的表达式也可以是一个逗号分隔的序列,后者生成一个元组)并且从左到右把单一的结果对象赋值给target_list的每一个元素。

赋值是递归定义的,取决于目标(序列)的形式。当目标是可变对象的一部分时(属性引用,下标或者切片),最终必须由该可变对象做赋值操作并决定其合法性,如果赋值不可接受可以抛出一个异常。各种类型遵守的规则以及抛出的异常根据对象类型的定义给出(参见标准类型的层次一节)。

赋值一个对象给一个目标序列按如下方式递归定义:

  • 如果对象列表是单一的目标:对象赋值给该目标。
  • 如果目标序列是逗号分隔的序列:对象必须是可迭代的且元素个数与目标序列中目标个数相同,然后元素从左向右赋值给对应的目标。

赋值一个对象给一个单一的目标按如下方式递归定义。

  • 如果目标是一个标识符(名称):

    • 如果名称没有出现在当前代码块的global语句中:名称绑定到当前局部命名空间中的对象。
    • 否则:名称绑定到当前全局命名空间的对象。

    如果名称已经绑定,那么它将重新绑定。这可能导致之前绑定到该名称的对象的引用计数变为零,引起该对象被释放并调用它的析构函数(如果有的话)。

  • 如果目标是一个包含在圆括号或者方括号中的目标序列:对象必须是可迭代的且元素个数与目标序列中目标个数相同,然后元素从左向右赋值给对应的目标。

  • 如果目标是属性引用:计算引用中的初级表达式。It should yield an object with assignable attributes; 如果情况不是这样,则抛出TypeError异常。That object is then asked to assign the assigned object to the given attribute; if it cannot perform the assignment, it raises an exception (usually but not necessarily AttributeError).

    注意:如果对象是类的实例且属性引用出现在赋值运算符的两侧,那么右侧的表达式a.x既可以访问实例属性(如果不存在实例属性)也可以访问类属性。左侧的目标将a.x永远设置成实例的属性,如果必要将创建它。因此,a.x的两次出现不是一定会引用同一个属性:如果右侧表达式引用的是一个类属性,左侧的表达式将创建一个新的实例属性作为赋值的目标。

    class Cls:
        x = 3             # class variable
    inst = Cls()
    inst.x = inst.x + 1   # writes inst.x as 4 leaving Cls.x as 3
    

    这里的描述不一定适用描述器属性,例如property()创建的属性。

  • 如果目标是下标操作符:计算引用中的初级表达式。It should yield either a mutable sequence object (such as a list) or a mapping object (such as a dictionary). Next, the subscript expression is evaluated.

    如果primary是一个可变的序列对象(例如一个列表),则下标必须产生一个普通的整数。如果它是负数,将会加上序列的长度。结果值必须是一个小于序列长度的非负整数,然后将要求序列赋值该对象给具有那个索引的元素。如果索引超出范围,则引发IndexError异常(给序列下标赋值不能添加新的元素到序列中)。

    如果primary 是一个映射对象(例如一个字典),下标必须具有和映射的关键字类型兼容的类型,然后要求映射创建一个键/值对将下标映射到赋值的对象。这既可以替换一个具有相同键值得已存在键/值对,也可以插入一个新的键/值对(如果不存在相同的键)。

  • 如果目标是一个切片:计算引用中的初级表达式。它应该产生一个可变序列对象(例如列表)。被赋值的对象应该是相同类型的序列对象。下一步,如果存在,则计算下边界和上边界表达式;默认是零和序列的长度。边界计算的值应该是(小)整数。如果任意一个边界为复数,则会给它加上序列的长度。结果求得的边界在零和序列的长度之间,包括边界在内。最后,要求序列对象用赋值的序列元素替换切片。切片的长度可能不同于赋值的序列的长度,因此如果对象允许则改变目标序列的长度。

CPython实现细节: In the current implementation, the syntax for targets is taken to be the same as for expressions, and invalid syntax is rejected during the code generation phase, causing less detailed error messages.

警告:虽然赋值的定义暗示左侧和右侧之间的交叉赋值是‘安全的’(例如,a, b = b, a交换两个变量),但是赋值目标集的内部有交叉则是不安全的!例如,下面的程序将打印[0, 2]

x = [0, 1]
i = 0
i, x[i] = 1, 2
print x

6.2.1. 增强的赋值语句

增强的赋值是将二元操作和赋值语句组合成一个单一的语句。

augmented_assignment_stmt ::=  augtarget augop (expression_list | yield_expression)
augtarget                 ::=  identifier | attributeref | subscription | slicing
augop                     ::=  "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="
                               | ">>=" | "<<=" | "&=" | "^=" | "|="

(最后三个符号的语法定义参见初级操作一节。)

增强的赋值将先求值target(和普通的赋值语句不同,它不可以是一个可拆分的对象)和expression_list,然后完成针对两个操作数的二元操作,最后将结果赋值给初始的target。target只计算一次。

x += 1这样增强的赋值表达式可以重写成x = x + 1以达到类似但不完全等同的效果。在增强版本中,x只计算一次。还有,如果可能,真实的操作是原地的,意思是不创建一个新的对象并赋值给target,而是直接修改旧的对象。

除了不可以在一个语句中赋值给元组和多个目标,增强的赋值语句完成的赋值和普通的赋值以相同的方式处理。类似地,除了可能出现的原地行为,增强的赋值完成的二元操作和普通的二元操作相同。

如果target是属性引用,关于类和实例属性的注意事项同样适用于正常的赋值。

6.3. assert 语句

Assert语句是插入调试断言到程序中的一种便捷方法:

assert_stmt ::=  "assert" expression ["," expression]

其简单形式,assert expression,等同于

if __debug__:
   if not expression: raise AssertionError

其扩展形式,assert expression1, expression2,等同于

if __debug__:
   if not expression1: raise AssertionError(expression2)

这些等价的语句假定__debug__AssertionError引用的是同名的内建变量。在当前的实现中,内建的变量__debug__在正常情况下为为True,在要求优化时(命令行选项-O)为False在编译时刻,当要求优化时,目前的代码生成器不会为断言语句生成任何代码。注:不必把失败的表达式的源代码包含进错误信息;它将作为栈回溯的一部分显示出来。

__debug__赋值是非法的。内建变量的值在解释器启动的时候就已决定。

6.4. pass 语句

pass_stmt ::=  "pass"

pass是一个空操作 — 执行它的时候,什么都没有发生。它的用处是当语法上要求有一条语句但是不需要执行任何代码的时候作为占位符,例如:

def f(arg): pass    # a function that does nothing (yet)

class C: pass       # a class with no methods (yet)

6.5. del 语句

del_stmt ::=  "del" target_list

删除是递归定义的,和赋值的定义方式非常相似。这里就不详细讲述完整的细节,只给出一些注意事项。

删除目标将从左向右递归删除每一个目标。

删除一个名称将从局部或全局命名空间中删除该名称的绑定,取决于名称是否出现在相同代码块的global语句中。如果名称没有绑定,将抛出一个NameError 异常。

如果名称作为自由变量出现在嵌套的代码块中,从局部命名空间中删除它是非法的。

属性引用、下标和切片的删除将传递给原始的对象;切片的删除在一般情况下等同于赋予一个右边类型的空切片(但即使这点也是由切片的对象决定)。

6.6. print 语句

print_stmt ::=  "print" ([expression ("," expression)* [","]]
                | ">>" expression [("," expression)+ [","]])

print依次计算每一个表达式并将求得的对象写入标准输出(参见下文)。如果对象不是字符串,那么首先使用字符串转换规则将它转换成字符串。然后输出(求得的或者原始的)字符串。在(转换并)输出每个对象之前会输出一个空格,除非输出系统认为它位于一行的开始。这些情况包括(1)还没有字符写入到标准输出,(2)写入到标准输出的最后一个字符是除' '以外的空白字符,或者(3)最后向标准输出写入的操作不是print语句。(在某些情况下由于这个原因向标准输出写入一个空白字符串可能是有用的。)

注意

行为像文件对象但是不是内建的文件对象的对象通常不会恰当地模拟文件对象的这方面行为,所以最好不要依赖这个行为。

在结尾会写入一个'\n'字符,除非print语句以逗号结束。如果语句只包含关键字print,这将是唯一的行为。

标准输出定义为内建模块sys中名为stdout的对象。 如果不存在该对象,或者它没有write()方法,将抛出一个RuntimeError异常。

print同样有一种扩展的形式,由上面描述的语法的第二部分定义。这种形式有时被称为“print chevron。” 在这种形式中,>>之后的第一个表达式必须是一个“类文件”对象,具体点就是具有上面提到的write()方法的对象。通过这种扩展形式,随后的表达式被输入到该文件对象。如果第一个表达式求值为None,那么使用sys.stdout作为输出的文件。

6.7. return 语句

return_stmt ::=  "return" [expression_list]

return在语法上只可以出现在函数定义中,不可以出现在类定义中。

如果存在expression_list,则计算它,否则使用None替换。

return离开当前的函数调用时以expression_list(或None)作为返回值。

return将控制传出带有finally子句的try语句时,在真正离开函数之前会执行finally子句。

在生成器函数中,return语句不允许包含expression_list在这种情况下,空的return表明生成器已经完成并将导致StopIteration异常抛出。

6.8. yield 语句

yield_stmt ::=  yield_expression

yield语句只在定义生成器函数时使用,且只在生成器函数的函数体中使用。在函数定义中使用yield语句就足以创建一个生成器函数而不是普通函数。

当调用生成器函数时,它返回一个称为生成器迭代器的迭代器,或者通常就叫做生成器。生成器函数体的执行通过重复调用生成器的next()方法直到它抛出一个异常。

当执行一个yield语句时,生成器的状态将冻结起来并且将expression_list的值返回给next()的调用者。“冻结”的意思是所有局部的状态都会被保存起来,包括当前局部变量的绑定、指令指针、内部的计算栈:保存足够的信息以使得下次调用next()时,函数可以准确地继续,就像yield语句只是另外一个外部调用。

从Python 2.5版开始,yield语句允许在出现在try ... finally结构的try子句中。如果生成器在终结(引用数达到零或者被当作垃圾回收)之前没有恢复,将调用生成器迭代器的close()方法, 这允许任何挂起的finally子句可以执行。

yield语义的完整细节,参考Yield表达式一节。

注意

在Python 2.2中,yield语句只有当generators功能启用了时才允许。__future__导入语句用来启用该功能:

from __future__ import generators

另请参阅

PEP 0255 - 简单的生成器
添加生成器和yield语句到Python中的提议。
PEP 0342 - 通过增强的生成器实现协程
该提议提出,除了其它的生成器的增强之外,允许yield出现在try ... finally代码块的内部。

6.9. raise 语句

raise_stmt ::=  "raise" [expression ["," expression ["," expression]]]

如果没有表达式,raise 重新抛出当前作用域中最后一个激活的异常。如果当前作用域中没有活动的异常,则抛出TypeError异常以表示这是一个错误(如果在IDLE中运行,则会抛出Queue.Empty异常)。

其他情况,raise分析后面的表达式以得到三个对象,使用None作为省略的表达式的值。前面的两个对象用于决定异常的类型

如果第一个对象是一个实例,那么异常的类型是实例的类,实例本身是值,第二个对象必须是None

如果第一个对象是一个类,那么它将成为异常的类型。第二个对象用于决定异常的值:如果它是类的实例,那么该实例将成为异常的值。如果第二个对象是一个元组,它用于类构造函数的参数列表;如果它是None,则使用一个空的参数列表,如果是其它任何对象则被当做构造函数的一个单一的参数。通过调用构造函数创建的实例将用作该异常的值。

如果存在第三个对象且不为None,那么它必须是一个回溯对象(参见标准类型的层次一节), 且它将替换当前异常发生的位置。如果存在第三个对象且值不是回溯对象或者None,将会抛出TypeError 异常。具有三个表达式形式的raise在处理except子句中显式地重新抛出异常这类问题是很有用,但是如果重新抛出的异常是当前作用域中最近激活的异常则应该优先使用不带表达式的raise

关于异常的更多信息可以在异常一节中找到,如何处理异常的信息在try语句一节。

6.10. break 语句

break_stmt ::=  "break"

break在语法上只可以出现在for或者while循环中,但不能嵌套在这些循环内的函数和类定义中。

它终止最相近的循环,如果循环有else子句将跳过。

如果break终止了一个for循环,控制循环的目标保持当前的值。

break将控制传出带有finally子句的try语句时,在离开循环之前会执行finally子句。

6.11. continue 语句

continue_stmt ::=  "continue"

continue在语法上只可以出现在forwhile循环中,但不能嵌套在这些循环内的函数定义、类定义和finally子句中。它继续最内层循环的下一轮。

continue将控制传出带有finally子句的try语句时,在真正开始下一轮循环之前会执行finally子句。

6.12. import 语句

import_stmt     ::=  "import" module ["as" name] ( "," module ["as" name] )*
                     | "from" relative_module "import" identifier ["as" name]
                     ( "," identifier ["as" name] )*
                     | "from" relative_module "import" "(" identifier ["as" name]
                     ( "," identifier ["as" name] )* [","] ")"
                     | "from" module "import" "*"
module          ::=  (identifier ".")* identifier
relative_module ::=  "."* module | "."+
name            ::=  identifier

import语句分两步执行:(1)找到模块,如果必要则进行初始化;(2)定义(import语句所在作用域的)局部命名空间中的名称。该语句有两种形式,区别在于有没有使用from关键字。第一种形式(没有from)针对序列中的每个标识符重复执行这些步骤。具有from的形式将先执行一次步骤(1),然后重复执行步骤(2)。

为了理解步骤(1)如何发生,你必须首先理解Python如何处理模块的分层命名。为了帮助组织模块并提供一套命名的层级,Python有一个包的概念。包可以包含其它包和模块,但是模块不可以包含其它模块或者包。从文件系统的角度,包是目录而模块是文件。原始的包的说明仍然可以阅读,尽管自从该文档的编写以来小的细节已经发生了变化。

一旦知道模块的名字(除非特别指出,“模块”这个词兼指包和模块),模块或者包的搜索就可以开始。首先检查的地方是sys.modules,这里是之前已经导入的所有模块的缓存。如果找到该模块,那么将在导入的步骤(2)使用它。

如果在缓存中没有找到该模块,则搜索sys.meta_pathsys.meta_path的说明可以在PEP 302中找到)。该对象是finder对象的一个列表,通过以模块的名称调用它们的find_module()方法可以知道如何加载模块。如果模块正好包含在某个包中(由名称中存在的点号表示),那么父包中的__path__属性将作为find_module() 第二个参数给出(正在导入的模块的名字中,最后一个点号之前的所有内容)。 如果某个finder能够找到该模块,它将返回一个loader(后面讨论)或者None

如果 sys.meta_path中finder 对象仍无法找到模块,便查找一些隐含定义的finder(如一个路径字符串由其处理时的特征可以当作一个隐含的finder).Python的不同实现在定义有哪些隐式的路径finder的集合时有所不同。然而,它们的定义都包括sys.path_hookssys.path_importer_cachesys.path

隐式finder在'两个地方之一'中指定的“路径”中搜索所请求的模块(“路径”不必是文件系统路径)。如果要导入的模块包含在包中,传递父包上的__ path __为第二个参数用作路径源给find_module(),。如果模块不包含在包中,则sys.path用作路径来源。

一旦路径源被选择,它被迭代以得到可以处理该路径的finder。字典sys.path_importer_cache会为 路径 缓存finder,并之后被使用查找finder。If the path does not have a finder cached then sys.path_hooks is searched by calling each object in the list with a single argument of the path, returning a finder or raises ImportError. If a finder is returned then it is cached in sys.path_importer_cache and then used for that path entry. If no finder can be found but the path exists then a value of None is stored in sys.path_importer_cache to signify that an implicit, file-based finder that handles modules stored as individual files should be used for that path. If the path does not exist then a finder which always returns None is placed in the cache for the path.

If no finder can find the module then ImportError is raised. Otherwise some finder returned a loader whose load_module() method is called with the name of the module to load (see PEP 302 for the original definition of loaders). A loader has several responsibilities to perform on a module it loads. First, if the module already exists in sys.modules (a possibility if the loader is called outside of the import machinery) then it is to use that module for initialization and not a new module. But if the module does not exist in sys.modules then it is to be added to that dict before initialization begins. If an error occurs during loading of the module and it was added to sys.modules it is to be removed from the dict. If an error occurs but the module was already in sys.modules it is left in the dict.

The loader must set several attributes on the module. __name__ is to be set to the name of the module. __file__ is to be the “path” to the file unless the module is built-in (and thus listed in sys.builtin_module_names) in which case the attribute is not set. If what is being imported is a package then __path__ is to be set to a list of paths to be searched when looking for modules and packages contained within the package being imported. __package__ is optional but should be set to the name of package that contains the module or package (the empty string is used for module not contained in a package). __loader__ is also optional but should be set to the loader object that is loading the module.

If an error occurs during loading then the loader raises ImportError if some other exception is not already being propagated. Otherwise the loader returns the module that was loaded and initialized.

当步骤(1)结束时没有抛出异常,步骤(2)就可以开始。

import语句的第一种形式将局部命名空间中的模块名绑定到模块对象,然后如果有下一个标识符则继续导入。如果模块后面带有as,则as后面的名称将用于模块的局部名称。

from形式不绑定模块的名称:它遍历标识符序列,在步骤(1)中找到的模块中逐一查找它们,然后绑定局部命名空间中的名称到找到的对象。与第一种形式的import类似,可以通过“as localname”提供另外一个名称。如果找不到名称,则引发ImportError如果用星号('*')替换标识符序列,那么模块中定义的所有公开的名称都将被绑定到import语句所在的局部命名空间。

模块定义的公开的名称通过检查模块命名空间中一个名为__all__的变量决定;如果定义,它必须是一个字符串序列,它们是该模块定义或者导入的名称。__all__中给出的名称都被认为是公开的且要求必须存在。如果__all__没有定义,那么公开的名称集合包括模块命名空间中找到的所有不是以下划线字符 ('_')开始的名称。__all__应该包含全部的公开API。它的意图是避免意外地导出不是API的部分(例如模块内部导入和使用的库模块)。

带有*from 形式只可以出现在模块作用域中。如果通配符形式的导入— import * — 在函数中使用并且函数包含或者是一个带有自由变量的嵌套代码块,编译器将抛出SyntaxError

When specifying what module to import you do not have to specify the absolute name of the module. When a module or package is contained within another package it is possible to make a relative import within the same top package without having to mention the package name. 通过在from之后指定的模块或包中使用前导的点号,你可以指定相对当前包层级向上移动的高度而不用指明准确的名称。一个前导的点号表示正在进行导入的模块所存在的包。两个点号表示向上一级。三个点表示向上两级,等等。所以如果你从pkg包的一个模块中执行from . import mod,那么你导入的将是pkg.mod如果你从pkg.subpkg1的内部执行from ..subpkg2 import mod,你将导入pkg.subpkg2.mod相对导入的说明包含在PEP 328中。

还提供importlib.import_module()以支持应用程序动态决定需要加载哪些模块。

6.12.1. Future 语句

future语句是一个针对编译器的指令,它指示某个特定的模块应该使用在未来版本的Python中可用的语法或者语义来编译。future语句的意图是使得迁移到未来版本的Python变得容易,这些未来版本向语言中引入了不兼容的变化。It allows use of the new features on a per-module basis before the release in which the feature becomes standard.

future_statement ::=  "from" "__future__" "import" feature ["as" name]
                      ("," feature ["as" name])*
                      | "from" "__future__" "import" "(" feature ["as" name]
                      ("," feature ["as" name])* [","] ")"
feature          ::=  identifier
name             ::=  identifier

future语句必须出现在靠近模块的顶部。出现在future语句之前的行只可以是:

  • 模块的文档字符串(如果有的话),
  • 注释,
  • 空白行,和
  • 其它future语句。

Python 2.6识别的特性有unicode_literalsprint_functionabsolute_importdivisiongeneratorsnested_scopeswith_statementgenerators, with_statement, nested_scopes在Python 2.6和更高的版本中是重复的,因为它们始终是被启用的。

future语句的识别和特殊处理在编译的时刻:核心语义的变化通常通过生成不同的代码实现。It may even be the case that a new feature introduces new incompatible syntax (such as a new reserved word), in which case the compiler may need to parse the module differently. Such decisions cannot be pushed off until runtime.

对于任何给定的版本,编译器知道哪些特性的名称已经定义了,如果future语句包含一个不认识的特性它将抛出编译时刻错误。

运行时刻的语义和任何import 语句是一样的:有一个标准的模块__future__(在后面讲述),它将在future语句执行的时候以正常的方式被导入。

The interesting runtime semantics depend on the specific feature enabled by the future statement.

Note that there is nothing special about the statement:

import __future__ [as name]

That is not a future statement; it’s an ordinary import statement with no special semantics or syntax restrictions.

在包含future语句的模块M中,exec语句编译的代码或者内建函数compile()execfile()的调用默认将使用与future语句关联的新的语法或语义。从Python 2.2开始,这种行为可以通过compile()可选的参数可以控制 — 详细信息参见该函数的文档。

A future statement typed at an interactive interpreter prompt will take effect for the rest of the interpreter session. If an interpreter is started with the -i option, is passed a script name to execute, and the script includes a future statement, it will be in effect in the interactive session started after the script is executed.

See also

PEP 236 - 回到__future__
__future__机制的原始提议。

6.13. global 语句

global_stmt ::=  "global" identifier ("," identifier)*

global语句是针对当前整个代码块的声明。It means that the listed identifiers are to be interpreted as globals. It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.

在相同的代码块中,global语句中列出的名称不可以在global语句之前使用。

global语句列出的名称不可定义为形式参数或者定义在for循环的控制目标、定义、函数定义或import语句中。

CPython implementation detail: The current implementation does not enforce the latter two restrictions, but programs should not abuse this freedom, as future implementations may enforce them or silently change the meaning of the program.

程序员提醒:global是针对解析器的指令。它只应用于与global语句同一时刻解析的代码。特别地,exec语句中包含的global语句不会影响包含exec语句的代码块,包含exec语句的代码中的global语句不影响exec语句中包含的代码。eval()execfile()compile()函数具有同样的机制。

6.14. exec 语句

exec_stmt ::=  "exec" or_expr ["in" expression ["," expression]]

该语句支持动态执行Python 代码。第一个表达式应该是Unicode 字符串,Latin-1 编码的字符串,文件对象,代码对象,或者元组。如果它是一个字符串,该字符串将被当做Python 语句组解析,然后执行(除非发生语法错误)。[1] 如果它是一个打开的文件,将解析该文件直到EOF并执行。如果它是一个代码对象,将简单地执行它。对于元组的解释,参见下文。对于所有的情况,都期望执行的代码和文件输入一样有效(参见文件输入一节)。注意即使在传递给exec语句的代码中,returnyield语句也不可以在函数定义之外使用。

在所有情况下,如果可选的部分被省略,代码将在当前的作用域中执行。如果in 之后给出第一个表达式,它应该是一个字典,全局和局部变量都将使用它。如果给出两个表达式,它们将分别用于全局和局部变量。如果给出,局部变量可以是任意一个映射对象。记住在模块级别,全局变量和局部变量是同一个字典。如果给出两个不同的对象作为全局变量局部变量,代码的执行将像是在类定义中一样。

第一个表达式也可以是一个长度为2或者3的元组。在这种情况下,可选的部分必须被省略。exec(expr, globals) 形式等同于exec expr in globals, 而exec(expr, globals, locals) 等同于exec expr in globals, localsexec 的元组形式提供了与Python 3的兼容性,在Python 3中exec 是一个函数而不是语句。

Changed in version 2.4: Formerly, locals was required to be a dictionary.

As a side effect, an implementation may insert additional keys into the dictionaries given besides those corresponding to variable names set by the executed code. 例如,当前的实现可能以键__builtins__添加一个指向内建模块__builtin__ 的引用(!)。

给程序员的提示:内建函数eval()支持动态计算表达式。内建函数 globals()locals()分别返回当前的全局变量和局部变量字典,可传递给exec使用。

Footnotes

[1]注意解析器只接受Unix风格的行结束惯例。如果你正在阅读一个文件中的代码,请确保使用统一的新行模式以转换Windows或Mac风格的换行。