python基础教程之复合语句

python基础教程之复合语句


8. 复合语句

复合语句包含(多组)其它语句;它们以某种方式影响或者控制其它那些语句的执行。通常,复合语句跨越多行,虽然一条完整的复合语句可以用简洁的形式包含在一行之中。

ifwhilefor语句实现传统的控制流句法结构。try specifies exception handlers and/or cleanup code for a group of statements, while the with statement allows the execution of initialization and finalization code around a block of code. 函数和类定义在语法上同样也是复合语句。

A compound statement consists of one or more ‘clauses.’ 一条子句由语句首和‘语句组’组成。一条特定的复合语句的所有子句的语句首都处在相同的缩进水平上。每一个子句的语句首以一个唯一的标识关键字开始并以冒号结束。语句组是由一条子句控制的一组语句。一个语句组可以是语句首冒号之后的同一行上紧跟一个或多个分号分隔的简单语句,也可以是后续行上一个或多个缩进的语句。Only the latter form of a suite can contain nested compound statements; 下面的语句是非法的,最主要是因为不能明确随后的else子句属于哪一个if子句:

if test1: if test2: print(x)

Also note that the semicolon binds tighter than the colon in this context, so that in the following example, either all or none of the print() calls are executed:

if x < y < z: print(x); print(y); print(z)

总结:

compound_stmt ::=  if_stmt
                   | while_stmt
                   | for_stmt
                   | try_stmt
                   | with_stmt
                   | funcdef
                   | classdef
suite         ::=  stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
statement     ::=  stmt_list NEWLINE | compound_stmt
stmt_list     ::=  simple_stmt (";" simple_stmt)* [";"]

注意语句永远以NEWLINE结束,其后可能跟随一个DEDENT还要注意可选的续行子句永远以一个不能作为语句开始的关键字开始,因此不会有歧义(‘悬挂的else’问题在Python中通过要求嵌套的if语句必须缩进得到解决)。

为了清晰起见,下面小节中的语法规则的格式会将子句放在单独的一行。


8.1. The if statement

The if 語句用於條件執行:

if_stmt ::=  "if" expression ":" suite
             ( "elif" expression ":" suite )*
             ["else" ":" suite]

它會逐個計算每一個表達式,直到發現其中一個條件為真,選出為真的那一個 參見*布爾運算* 定義的真假;然後該套件執行(且不再執行或判斷其它if語句)。如果所有表達式為假,執行 else 語句。


8.2.  while 语句

 while 语句用于在表达式正确的条件下重复执行

while_stmt ::=  "while" expression ":" suite
                ["else" ":" suite]

它重复测试表达式,如果为真,则执行第一个语句组;如果表达式为假(可能是第一次测试),则执行else子句且终止循环。

第一个语句组中执行的break语句会终止循环而不执行else子句的语句组。在第一个语句组中执行的continue语句会跳过语句组中剩余的语句并返回继续测试表达式。


8.3. The for statement

for语句用于迭代一个序列的元素(例如字符串、元组或者列表)或者其它可迭代的对象:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

表达式列表值计算一次;它应当产生一个可迭代的对象。expression_list的结果创建一个迭代器。The suite is then executed once for each item provided by the iterator, in the order returned by the iterator. Each item in turn is assigned to the target list using the standard rules for assignments (see Assignment statements), and then the suite is executed. When the items are exhausted (which is immediately when the sequence is empty or an iterator raises a StopIteration exception), the suite in the else clause, if present, is executed, and the loop terminates.

第一个语句组中执行的break语句会终止循环而不执行else子句的语句组。A continue statement executed in the first suite skips the rest of the suite and continues with the next item, or with the else clause if there is no next item.

The for-loop makes assignments to the variables(s) in the target list. This overwrites all previous assignments to those variables including those made in the suite of the for-loop:

for i in range(10):
    print(i)
    i = 5             # this will not affect the for-loop
                      # because i will be overwritten with the next
                      # index in the range

Names in the target list are not deleted when the loop is finished, but if the sequence is empty, they will not have been assigned to at all by the loop. Hint: the built-in function range() returns an iterator of integers suitable to emulate the effect of Pascal’s for i := a to b do; e.g., list(range(3)) returns the list [0, 1, 2].

注意

当序列被循环修改时,会发生微妙的事情(只有可变类型的序列会发生,例如列表)。有一个内部计数器用于跟踪下一轮循环使用哪一个元素,并且每次迭代中会增加。 当计数器达到序列的长度时循环终止。这意味着如果语句组从序列中删除当前(或者前面的)元素,下一个元素将被跳过(因为它获取当前已经被处理过的元素的索引)。同样地,如果语句组在序列中当前元素之前插入一个元素,那么当前元素将在下一次循环被再次处理。这可能导致难以觉察的错误,但可以通过使用整个序列的切片生成临时拷贝避免这个问题,例如,

for x in a[:]:
    if x < 0: a.remove(x)

8.4. The try statement

try语句为一组语句指定异常处理器和/或清理代码:

try_stmt  ::=  try1_stmt | try2_stmt
try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try2_stmt ::=  "try" ":" suite
               "finally" ":" suite

except子句指定一个或多个异常处理器.。try子句中没有出现异常时,不会执行异常处理器。try语句组中出现异常时,开始搜索异常处理器。 搜索依次检查异常子句直到找到与异常匹配的一个。没有表达式的异常子句,如果出现,必须放在最后;它匹配任何异常。对于一个带有表达式的异常子句,该表达式将被求值,如果结果对象与异常“兼容”,则认为子句与异常匹配。An object is compatible with an exception if it is the class or a base class of the exception object or a tuple containing an item compatible with the exception.

如果没有except子句匹配到异常,异常处理器的搜索将继续在外层代码和调用栈上进行。 [1]

如果计算except子句头部的一个表达式引发了异常, 那么就会中断原异常处理器的搜索, 而在外层代码和调用栈上搜索新的异常处理器(就好像是整个try语句发生了异常一样)。

When a matching except clause is found, the exception is assigned to the target specified after the as keyword in that except clause, if present, and the except clause’s suite is executed. 所有的异常子句必须具有一个可执行的代码块。当到达该代码块的结尾时,在真个try语句之后执行正常继续。(这意味着如果同一个异常存在两个嵌套的处理器,且异常发生在内部处理器的try子句中,那么外边的处理器不会处理这个异常。)

When an exception has been assigned using as target, it is cleared at the end of the except clause. This is as if

except E as N:
    foo

was translated to

except E as N:
    try:
        foo
    finally:
        del N

This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.

Before an except clause’s suite is executed, details about the exception are stored in the sys module and can be accessed via sys.exc_info(). sys.exc_info() returns a 3-tuple consisting of the exception class, the exception instance and a traceback object (see section The standard type hierarchy) identifying the point in the program where the exception occurred. sys.exc_info() values are restored to their previous values (before the call) when returning from a function that handled an exception.

如果控制流从try子句的结尾出来时,则执行可选的else子句。[2]else子句中的异常不会被前面的except子句处理。

如果有finally出现,它指定一个“清除”处理器。首先执行try子句被执行,然后包括任何exceptelse子句。如果异常发生在任何子句中且没有被处理,那么异常会被临时保存起来。最后执行finally子句。If there is a saved exception it is re-raised at the end of the finally clause. If the finally clause raises another exception, the saved exception is set as the context of the new exception. If the finally clause executes a return or break statement, the saved exception is discarded:

>>> def f():
...     try:
...         1/0
...     finally:
...         return 42
...
>>> f()
42

finally子句执行过程中程序访问不到异常信息。

When a return, break or continue statement is executed in the try suite of a tryfinally statement, the finally clause is also executed ‘on the way out.’ continue语句出现在finally子句中是非法的。(原因是当前实现的问题 — 该限制在未来可能会去掉)。

函数的返回值取决于执行的最后一条return语句。因为finally子句会永远执行,在finally子句中执行的return语句将永远是最后执行的一条语句:

>>> def foo():
...     try:
...         return 'try'
...     finally:
...         return 'finally'
...
>>> foo()
'finally'

额外的信息可以在异常一节中找到,关于如何使用raise语句产生异常可以在raise语句一节中找到。


8.5. The with statement

with用于和上下文管理器定义的方法一起封装代码块的执行(参见With语句的上下文管理器一节)。This allows common tryexceptfinally usage patterns to be encapsulated for convenient reuse.

with_stmt ::=  "with" with_item ("," with_item)* ":" suite
with_item ::=  expression ["as" target]

带有一个“item”的with语句的执行按下面的方式进行:

  1. 计算上下文表达式(with_item中给出的表达式)以获得一个上下文管理器。

  2. 加载上下文管理器的__exit__()方法留着后面使用。

  3. 调用上下文管理器的__enter__()方法。

  4. 如果with语句包含一个目标,__enter__()的返回值将赋值给它。

    注意

    with语句保证如果__enter__()方法没有错误返回,那么__exit__()将永远被调用。因此,如果在给目标列表赋值过程中出现错误,它将被与语句组中发生的错误同样对待。参见下面的第6步。

  5. 执行语句组。
  6. 调用上下文管理器的__exit__()方法。如果异常导致语句组要退出,那么异常的类型、值和回溯栈被当做参数传递给__exit__()Otherwise, three None arguments are supplied.

    如果语句组由于异常退出,且__exit__()方法的返回值为假,异常将被重新引发。如果返回值为真,异常将被取消,并继续执行with语句之后的语句。

    如果语句组由于异常以外的其它任何原因退出,__exit__()的返回值将被忽略,执行将在退出发生的正常位置继续。

如果有多个条目,上下文管理器的处理如同嵌套的多个with语句:

with A() as a, B() as b:
    suite

等同于

with A() as a:
    with B() as b:
        suite

Changed in version 3.1: 支持多个上下文表达式。

请参阅

PEP 0343 – The “with” statement
Python with语句的说明、背景和实例。

8.6. Function definitions

函数定义定义一个用户自定义的函数对象(参见标准类型的层次一节):

funcdef        ::=  [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite
decorators     ::=  decorator+
decorator      ::=  "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE
dotted_name    ::=  identifier ("." identifier)*
parameter_list ::=  (defparameter ",")*
                    | "*" [parameter] ("," defparameter)* ["," "**" parameter]
                    | "**" parameter
                    | defparameter [","] )
parameter      ::=  identifier [":" expression]
defparameter   ::=  parameter ["=" expression]
funcname       ::=  identifier

函数定义是一个可执行的语句。它的执行将绑定当前局部命名空间中的函数名到一个函数对象(函数可执行代码的封装)。函数对象包含一个对当前全局命名空间的引用,作为函数调用时使用的全局命名空间。

函数定义不会执行函数体;它只有在调用函数的时候才执行。[3]

函数定义可能被一个或多个修饰符表达式封装。修饰符表达式在函数定义时于包含函数定义的定义域中求值。求值的结果必须是一个可调用对象,它以该函数对象为唯一的参数。调用的返回值绑定在函数名而不是函数对象上。多个修饰符是以嵌套的方式作用的。例如,下面的代码

@f1(arg)
@f2
def func(): pass

等同于

def func(): pass
func = f1(arg)(f2(func))

When one or more parameters have the form parameter = expression, the function is said to have “default parameter values.” 对于具有默认值的参数,对应的参数在调用时可以省略,在这种情况下使用参数的默认值。If a parameter has a default value, all following parameters up until the “*” must also have a default value — this is a syntactic restriction that is not expressed by the grammar.

Default parameter values are evaluated from left to right when the function definition is executed. 这意味着只在函数定义的时候该表达式求一次值,以后每次调用使用相同的“提前计算好的”值。这对于理解默认参数是可变对象时特别重要,例如列表或字典:如果函数修改了该对象(例如,向列表添加一个元素),默认值将受影响被修改。这通常不是想要的。A way around this is to use None as the default, and explicitly test for it in the body of the function, e.g.:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

函数调用的语义在调用一节有更详细的描述。函数调用永远会给参数列表中的所有的参数赋值,无论是位置参数还是关键字参数或默认值。如果出现“*identifier”的形式,那么它被初始化为一个可以接收任意多余位置参数元组,默认为空元组。如果有“**identifier”的形式,那么它被初识化为一个可以接收任意的多余关键字参数的新的字典,默认值为空字典。Parameters after “*” or “*identifier” are keyword-only parameters and may only be passed used keyword arguments.

Parameters may have annotations of the form “: expression” following the parameter name. Any parameter may have an annotation even those of the form *identifier or **identifier. Functions may have “return” annotation of the form “-> expression” after the parameter list. These annotations can be any valid Python expression and are evaluated when the function definition is executed. Annotations may be evaluated in a different order than they appear in the source code. The presence of annotations does not change the semantics of a function. The annotation values are available as values of a dictionary keyed by the parameters’ names in the __annotations__ attribute of the function object.

也可以创建匿名函数(没有绑定到某个名称的函数),以在表达式中直接使用。它使用lambda 表达式,在Lambdas一节中有详细描述。注意lambda 表达式仅仅是简单的函数定义的简写;def”语句中定义的函数和lambda 表达式定义的函数一样,可以传递或者赋值给另外一个名称。The “def” form is actually more powerful since it allows the execution of multiple statements and annotations.

程序员的注意事项: 函数是第一级的对象。A “def” statement executed inside a function definition defines a local function that can be returned or passed around. 在嵌套的函数中使用的自由变量可以访问包含该def的函数的局部变量。详细信息参见名称和绑定一节。

请参阅

PEP 3107 – Function Annotations
The original specification for function annotations.

8.7. Class definitions

类定义定义一个类对象(参见标准类型的层次 一节):

classdef    ::=  [decorators] "class" classname [inheritance] ":" suite
inheritance ::=  "(" [parameter_list] ")"
classname   ::=  identifier

类定义是一个可执行语句。The inheritance list usually gives a list of base classes (see Customizing class creation for more advanced uses), so each item in the list should evaluate to a class object which allows subclassing. Classes without an inheritance list inherit, by default, from the base class object; hence,

class Foo:
    pass

等同于

class Foo(object):
    pass

The class’s suite is then executed in a new execution frame (see Naming and binding), using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly function definitions.) 当类的语句组结束执行,它的执行帧被丢弃但是局部命名空间被保存下来。[4]最后使用inheritance序列作为基类创建一个类对象,并保存局部命名空间作为属性字典。类的名称被绑定到初识局部命名空间中类对象。

Class creation can be customized heavily using metaclasses.

Classes can also be decorated: just like when decorating functions,

@f1(arg)
@f2
class Foo: pass

等同于

class Foo: pass
Foo = f1(arg)(f2(Foo))

The evaluation rules for the decorator expressions are the same as for function decorators. 结果必须是一个类对象,并绑定于类的名字。

程序员的注意事项: Variables defined in the class definition are class attributes; they are shared by instances. Instance attributes can be set in a method with self.name = value. Both class and instance attributes are accessible through the notation “self.name”, and an instance attribute hides a class attribute with the same name when accessed in this way. Class attributes can be used as defaults for instance attributes, but using mutable values there can lead to unexpected results. Descriptors can be used to create instance variables with different implementation details.

请参阅

PEP 3115 – Metaclasses in Python 3 PEP 3129 – Class Decorators

脚注

[1] 异常将扩散到调用栈除非finally子句碰巧引发另外一个异常。这个新的异常导致旧的异常丢失。
[2] 目前,控制“从末尾流出”除了下面这些情况:异常或执行returncontinuebreak语句。
[3] 作为函数体第一条语句出现的字符串字面值被转换成函数的__doc__属性,即函数的文档字符串
[4] 作为类体的第一条语句出现的语句被转换为该命名空间的__doc__属性,即类的文档字符串

留下回复