Skip to main content

6. 表达式

本章解释Python中表达式元素的含义。

语法注: 在本章和后续章节中,扩展BNF符号将用于描述语法,而不是词法分析。语法规则(一种替代形式)具有形式

name ::=  othername

并且没有给出语义,这种形式的 name 的语义与 othername 相同。

6.1. 算术转换

当下面的算术运算符的描述使用短语“数字参数被转换为公共类型”时,这意味着内置类型的运算符实现工作如下:

  • 如果任一参数是复数,则将另一个转换为复数;

  • 否则,如果任一参数是浮点数,则将另一个转换为浮点数;

  • 否则,两者必须是整数,不需要转换。

一些附加规则适用于某些运算符(例如,字符串作为’%’运算符的左参数)。扩展程序必须定义自己的转换行为。

6.2. 原子

原子是表达式中最基本的元素。最简单的原子是标识符或文字。括号在括号,括号或大括号中的表单也在句法上被归类为原子。原子的语法是:

atom      ::=  identifier | literal | enclosure
enclosure ::=  parenth_form | list_display | dict_display | set_display
               | generator_expression | yield_atom

6.2.1. 标识符(名称)

作为原子出现的标识符是名称。有关命名和绑定的文档,请参见 标识符和关键字 部分的词汇定义和 命名和绑定 部分。

当名称绑定到对象时,原子的求值得到该对象。当名称未绑定时,尝试评估它会引发 NameError 异常。

私人名称: 当在类定义中文本出现的标识符以两个或多个下划线字符开头,并且不以两个或多个下划线结尾时,它被认为是该类的 private name。在为其生成代码之前,专用名称将转换为较长的形式。转换插入类名称,并在名称前面删除前导下划线并插入一个下划线。例如,出现在名为 Ham 的类中的标识符 __spam 将被转换为 _Ham__spam。这种变换独立于使用标识符的语法上下文。如果转换的名称非常长(超过255个字符),可能会发生实现定义的截断。如果类名称仅由下划线组成,则不进行转换。

6.2.2. 文字

Python支持字符串和字节字面量和各种数字文字:

literal ::=  stringliteral | bytesliteral
             | integer | floatnumber | imagnumber

字面量的求值产生给定类型(字符串,字节,整数,浮点数,复数)与给定值的对象。该值可以在浮点和虚(复数)文字的情况下近似。有关详细信息,请参阅 文字 部分。

所有文本对应于不可变的数据类型,因此对象的身份比其值更不重要。对具有相同值(在程序文本中相同的出现或不同的出现)的文字的多次求值可以获得相同的对象或具有相同值的不同对象。

6.2.3. 括号形式

括号形式是括在括号中的可选表达式列表:

parenth_form ::=  "(" [starred_expression] ")"

括号表达式列表产生表达式列表产生的任何内容:如果列表包含至少一个逗号,则它产生一个元组;否则,它产生组成表达式列表的单个表达式。

一对空圆括号产生一个空的元组对象。因为元组是不可变的,所以文字的规则适用(即,空元组的两次出现可能或可能不会产生相同的对象)。

注意,元组不是由括号形成的,而是通过使用逗号运算符。异常是空的元组,对于它需要使用括号 are —允许表达式中不带括号的“无”将导致歧义,并允许常见的拼写错误通过未捕获。

6.2.4. 显示列表,集和字典

对于构造列表,集合或字典,Python提供了一种称为“显示”的特殊语法,它们各有两种类型:

  • 或者容器内容被明确列出

  • 它们通过称为 comprehension 的一组循环和过滤指令来计算。

用于推导的常见语法元素为:

comprehension ::=  expression comp_for
comp_for      ::=  [ASYNC] "for" target_list "in" or_test [comp_iter]
comp_iter     ::=  comp_for | comp_if
comp_if       ::=  "if" expression_nocond [comp_iter]

该理解由一个单一表达式,后面至少一个 for 子句和零个或多个 forif 子句组成。在这种情况下,新容器的元素是通过考虑每个 forif 子句从左到右嵌套的块,并且在每次到达最内部块时评估表达式以产生元素的元素。

注意,理解在单独的范围中执行,因此在目标列表中分配的名称不会“泄漏”到封闭范围中。

从Python 3.6开始,在 async def 函数中,可以使用 async for 子句来遍历 asynchronous iteratorasync def 函数中的理解可以由跟随在前导表达式之后的 forasync for 子句组成,可以包含额外的 forasync for 子句,并且还可以使用 await 表达式。如果一个解释包含 async for 子句或 await 表达式,它被称为 asynchronous comprehension。异步理解可以暂停它出现的协同程序函数的执行。参见 PEP 530

6.2.5. 列表显示

列表显示是用方括号括起来的可能为空的一系列表达式:

list_display ::=  "[" [starred_list | comprehension] "]"

列表显示产生一个新的列表对象,其内容由表达式列表或推理指定。当提供以逗号分隔的表达式列表时,将从左到右计算其元素,并按该顺序放置到列表对象中。当提供理解时,从由理解产生的元素构造列表。

6.2.6. 设置显示

设置显示由大括号表示,并且通过缺少分隔键和值的冒号而与字典显示区分开:

set_display ::=  "{" (starred_list | comprehension) "}"

设置显示产生一个新的可变集合对象,其内容由表达式序列或理解指定。当提供以逗号分隔的表达式列表时,将从左到右计算其元素,并将其添加到设置的对象。当提供理解时,从由理解产生的元素构建集合。

空集不能用 {} 构造;这个文字构造一个空字典。

6.2.7. 字典显示

字典显示是用大括号括起来的可能为空的一系列键/基准对:

dict_display       ::=  "{" [key_datum_list | dict_comprehension] "}"
key_datum_list     ::=  key_datum ("," key_datum)* [","]
key_datum          ::=  expression ":" expression | "**" or_expr
dict_comprehension ::=  expression ":" expression comp_for

字典显示产生新的字典对象。

如果给出了以逗号分隔的键/数据对序列,则从左到右对它们求值以定义字典的条目:每个键对象用作字典中的键以存储相应的数据。这意味着您可以在键/基准列表中多次指定相同的键,并且该键的最终字典值将是最后一个给定的值。

双星号 ** 表示 dictionary unpacking。其操作数必须是 mapping。每个映射项都将添加到新字典。稍后的值替换早期键/数据对和早期字典解包中已设置的值。

3.5 新版功能: 开箱到字典显示,最初由 PEP 448 提出。

与列表和集合的理解相反,dict的理解需要两个用冒号分隔的表达式,后跟通常的“for”和“if”子句。运行理解时,生成的键和值元素将按照生成的顺序插入新字典。

关于键值类型的限制在 标准类型层次结构 部分的前面列出。 (总而言之,键类型应该是 hashable,其排除所有可变对象。)未检测到重复键之间的冲突;对于给定键值存储的最后一个数据(在显示器中的文本最右侧)占优势。

6.2.8. 生成器表达式

生成器表达式是括号中的紧凑生成器符号:

generator_expression ::=  "(" expression comp_for ")"

生成器表达式生成新的生成器对象。它的语法与对于理解相同,除了它被括在括号中而不是括号或大括号中。

当为生成器对象调用 __next__() 方法时(以与正常生成器相同的方式),在生成器表达式中使用的变量会被延迟评估。但是,最左侧的 for 子句会立即被求值,因此可以在处理生成器表达式的代码中的任何其他可能的错误之前看到它产生的错误。后续的 for 子句不能被立即计算,因为它们可能取决于先前的 for 循环。例如:(x*y for x in range(10) for y in bar(x))

在只有一个参数的调用中可以省略括号。有关详细信息,请参阅 呼叫 部分。

从Python 3.6开始,如果生成器出现在 async def 函数中,则允许 async for 子句和 await 表达式,就像异步理解一样。如果生成器表达式包含 async for 子句或 await 表达式,它被称为 asynchronous generator expression。异步生成器表达式产生一个新的异步生成器对象,它是一个异步迭代器(见 异步迭代器)。

6.2.9. 产量表达式

yield_atom       ::=  "(" yield_expression ")"
yield_expression ::=  "yield" [expression_list | "from" expression]

yield表达式在定义 generator 函数或 asynchronous generator 函数时使用,因此只能在函数定义的主体中使用。在函数体中使用yield表达式会使该函数成为一个生成器,并且在 async def 函数体中使用它会导致该协同程序函数成为一个异步生成器。例如:

def gen():  # defines a generator function
    yield 123

async def agen(): # defines an asynchronous generator function (PEP 525)
    yield 123

下面描述发电机功能,而在 异步发生器功能 章节中分别描述异步发电机功能。

当调用生成器函数时,它返回一个称为生成器的迭代器。然后,该生成器控制生成器函数的执行。当一个生成器的方法被调用时,执行开始。在那时,执行进行到第一个yield表达式,在那里它被再次挂起,将 expression_list 的值返回给生成器的调用者。通过暂停,我们意味着保留所有本地状态,包括局部变量的当前绑定,指令指针,内部计算堆栈和任何异常处理的状态。当通过调用其中一个生成器的方法来恢复执行时,该函数可以像yield表达式只是另一个外部调用一样进行。恢复后的yield表达式的值取决于恢复执行的方法。如果使用 __next__() (通常通过 fornext() 内置),则结果是 None。否则,如果使用 send(),则结果将是传递到该方法的值。

所有这些使得生成器函数非常类似于协同程序;它们产生多次,它们具有多个入口点并且它们的执行可以被暂停。唯一的区别是生成器函数不能控制执行在它产生后继续执行的位置;控制总是转移到发电机的调用者。

屈服表达式允许在 try 结构中的任何地方。如果生成器在最终确定之前没有恢复(通过达到零引用计数或通过垃圾收集),将调用生成器迭代器的 close() 方法,允许执行任何未决的 finally 子句。

当使用 yield from <expr> 时,它将提供的表达式视为辅助参数。由该subiterator产生的所有值直接传递给当前生成器的方法的调用者。使用 send() 传递的任何值和使用 throw() 传递的任何异常都会传递给底层迭代器(如果它具有适当的方法)。如果不是这样,那么 send() 将提高 AttributeErrorTypeError,而 throw() 将立即提高传递的异常。

当底层迭代器完成时,生成的 StopIteration 实例的 value 属性将成为yield表达式的值。它可以在提高 StopIteration 时显式设置,也可以在子迭代器是一个生成器时自动设置(通过从子生成器返回一个值)。

在 3.3 版更改: 添加了 yield from <expr> 以将控制流委派给子计算器。

当yield表达式是赋值语句右侧的唯一表达式时,可以省略括号。

参见

PEP 255 - 简单发电机

将生成器和 yield 语句添加到Python的提议。

PEP 342 - 协同通过增强的发电机

增强生成器的API和语法的建议,使它们可以用作简单的协同程序。

PEP 380 - 用于委派给子生成器的语法

介绍 yield_from 语法的建议,使委派给子生成器容易。

6.2.9.1. 生成器迭代器方法

本小节描述了生成器迭代器的方法。它们可以用于控制生成函数的执行。

注意,当发生器已经执行时,调用下面的任何generator方法都会引发 ValueError 异常。

generator.__next__()

开始执行生成函数或在最后执行的yield表达式恢复它。当使用 __next__() 方法恢复生成函数时,当前收益率表达式总是评估为 None。然后,执行继续到下一个yield表达式,其中生成器再次挂起,并且 expression_list 的值返回给 __next__() 的调用者。如果生成器退出而不产生另一个值,则会引发 StopIteration 异常。

该方法通常被隐式地调用,例如。通过 for 循环,或通过内置的 next() 功能。

generator.send(value)

恢复执行并将值“发送”到生成器函数中。 value 参数成为当前yield表达式的结果。 send() 方法返回由生成器生成的下一个值,如果生成器退出而不产生另一个值,则提高 StopIteration。当调用 send() 来启动生成器时,必须使用 None 作为参数来调用它,因为没有可以接收该值的yield表达式。

generator.throw(type[, value[, traceback]])

在生成器暂停的点上引发 type 类型的异常,并返回生成器函数产生的下一个值。如果生成器退出而不产生另一个值,则会引发 StopIteration 异常。如果生成器函数没有捕获传入的异常,或引发不同的异常,那么该异常传播到调用者。

generator.close()

在生成函数暂停的点上升 GeneratorExit。如果生成器函数然后正常退出,已经关闭,或者提高 GeneratorExit (通过不捕获异常),close将返回其调用者。如果发生器产生一个值,则 RuntimeError 被升高。如果生成器引发任何其他异常,它将传播到调用者。如果发电机由于异常或正常退出已经退出,则 close() 不执行任何操作。

6.2.9.2. 例子

这里是一个简单的例子演示发电机和发电机功能的行为:

>>> def echo(value=None):
...     print("Execution starts when 'next()' is called for the first time.")
...     try:
...         while True:
...             try:
...                 value = (yield value)
...             except Exception as e:
...                 value = e
...     finally:
...         print("Don't forget to clean up when 'close()' is called.")
...
>>> generator = echo(1)
>>> print(next(generator))
Execution starts when 'next()' is called for the first time.
1
>>> print(next(generator))
None
>>> print(generator.send(2))
2
>>> generator.throw(TypeError, "spam")
TypeError('spam',)
>>> generator.close()
Don't forget to clean up when 'close()' is called.

有关使用 yield from 的示例,请参阅“Python的新增功能”中的 PEP 380:委派给子生成器的语法

6.2.9.3. 异步发生器功能

在使用 async def 定义的函数或方法中的产量表达的存在进一步将该函数定义为 asynchronous generator 函数。

当调用异步生成器函数时,它返回一个称为异步生成器对象的异步迭代器。然后该对象控制生成器函数的执行。异步生成器对象通常用在协同程序函数中的 async for 语句中,类似于在 for 语句中如何使用生成器对象。

调用异步生成器的方法之一将返回一个 awaitable 对象,并且当该对象被等待时,执行开始。在那时,执行进行到第一个yield表达式,其中它被再次挂起,将 expression_list 的值返回到等待协同。与生成器一样,挂起意味着保留所有本地状态,包括局部变量的当前绑定,指令指针,内部计算堆栈和任何异常处理的状态。当通过等待异步生成器的方法返回的下一个对象来恢复执行时,该函数可以完全如同yield表达式只是另一个外部调用那样进行。恢复后的yield表达式的值取决于恢复执行的方法。如果使用 __anext__(),则结果是 None。否则,如果使用 asend(),则结果将是传递到该方法的值。

在异步生成器函数中,允许yield表达式在 try 结构中的任何位置。然而,如果异步生成器在最终确定(通过达到零引用计数或通过垃圾收集)之前没有恢复,则 try 构造内的yield表达式可能导致执行未决的 finally 子句失败。在这种情况下,运行异步生成器的事件循环或调度程序的责任是调用异步生成器 - 迭代器的 aclose() 方法并运行生成的协同程序对象,从而允许任何未决的 finally 子句执行。

为了处理最终化,事件循环应该定义一个 finalizer 函数,该函数接收异步生成器 - 迭代器并且可能调用 aclose() 并执行协同程序。此 finalizer 可通过致电 sys.set_asyncgen_hooks() 注册。当第一次迭代时,异步生成器 - 迭代器将存储注册的 finalizer,以在最终化时被调用。对于 finalizer 方法的参考示例,参见 asyncio.Loop.shutdown_asyncgensLib/asyncio/base_events.py 中的实现。

当在异步生成器函数中使用时,表达式 yield from <expr> 是语法错误。

6.2.9.4. 异步生成器 - 迭代器方法

本小节描述了异步生成器迭代器的方法,用于控制生成器函数的执行。

coroutine agen.__anext__()

返回一个等待,当运行开始执行异步生成器或恢复在最后执行的yield表达式。当使用 __anext__() 方法恢复异步生成器函数时,当前yield表达式总是在返回的awaitable中计算为 None,当运行时将继续到下一个yield表达式。 yield表达式的 expression_list 的值是完成协同程序引发的 StopIteration 异常的值。如果异步发生器退出而不产生另一个值,则等待会引发 StopAsyncIteration 异常,表明异步迭代已完成。

此方法通常由 async for 循环隐式调用。

coroutine agen.asend(value)

返回等待,当运行恢复异步生成器的执行时。与用于发生器的 send() 方法一样,这将“发送”一个值到异步生成器函数中,并且 value 自变量成为当前产量表达式的结果。 asend() 方法返回的awaitable将返回由生成器产生的下一个值作为提升的 StopIteration 的值,或者如果异步生成器退出而不产生另一个值,则提高 StopAsyncIteration。当 asend() 被调用以启动异步生成器时,必须使用 None 作为参数来调用它,因为没有可以接收该值的yield表达式。

coroutine agen.athrow(type[, value[, traceback]])

返回在异步生成器暂停时引发 type 类型异常的awaitable,并返回生成器函数生成的下一个值作为生成的 StopIteration 异常的值。如果异步生成器退出而不产生另一个值,则 StopAsyncIteration 异常由等待产生。如果生成器函数没有捕获传入的异常,或引发不同的异常,那么当运行awaitalbe时,异常传播到等待的调用者。

coroutine agen.aclose()

返回一个等待,当运行将 GeneratorExit 抛出异步生成器函数在它被暂停的点。如果异步生成器函数然后正常退出,已经关闭,或者引发 GeneratorExit (通过不捕获异常),则返回的等待将引发 StopIteration 异常。任何由后续调用异步发生器返回的等待将产生 StopAsyncIteration 异常。如果异步发生器产生一个值,则 RuntimeError 由等待产生。如果异步发生器引发任何其他异常,则将其传播给等待的调用者。如果异步生成器已经由于异常或正常退出而退出,则对 aclose() 的进一步调用将返回不起作用的等待。

6.3. 主要

原语表示语言的最紧密绑定的操作。它们的语法是:

primary ::=  atom | attributeref | subscription | slicing | call

6.3.1. 属性引用

属性引用是主域名,后跟有句点和名称:

attributeref ::=  primary "." identifier

主要必须评估支持属性引用的类型的对象,大多数对象做的。然后要求该对象生成名称为标识符的属性。这种生产可以通过重写 __getattr__() 方法来定制。如果此属性不可用,则引发异常 AttributeError。否则,生成的对象的类型和值由对象确定。对同一属性引用的多次评估可能产生不同的对象。

6.3.2. 订阅

订阅选择序列(字符串,元组或列表)或映射(字典)对象的项目:

subscription ::=  primary "[" expression_list "]"

主体必须评估支持预订的对象(例如列表或字典)。用户定义的对象可以通过定义 __getitem__() 方法来支持预订。

对于内置对象,有两种类型的对象支持订阅:

如果主映射是映射,则表达式列表必须求值为其值为映射键之一的对象,并且预订选择与该键对应的映射中的值。 (表达式列表是一个元组,除非它只有一个项目。)

如果主要是序列,则表达式(列表)必须求值为整数或切片(如下一节中所述)。

形式语法对序列中的负索引没有特殊规定;然而,内置序列都提供了通过将序列的长度加到索引来解释负索引的 __getitem__() 方法(以便 x[-1] 选择 x 的最后一项)。结果值必须是小于序列中项目数的非负整数,并且预订选择其索引为该值的项目(从零开始计数)。由于对象的 __getitem__() 方法支持负索引和切片,因此覆盖此方法的子类将需要显式地添加该支持。

字符串的项目是字符。字符不是单独的数据类型,而是一个正好一个字符的字符串。

6.3.3. 切片

切片选择序列对象中的项目范围(例如,字符串,元组或列表)。切片可用作分配或 del 语句中的表达式或目标。切片的语法:

slicing      ::=  primary "[" slice_list "]"
slice_list   ::=  slice_item ("," slice_item)* [","]
slice_item   ::=  expression | proper_slice
proper_slice ::=  [lower_bound] ":" [upper_bound] [ ":" [stride] ]
lower_bound  ::=  expression
upper_bound  ::=  expression
stride       ::=  expression

这里的形式语法有歧义:任何看起来像表达式列表的东西看起来像一个切片列表,所以任何订阅都可以被解释为切片。不是进一步使语法复杂化,而是通过定义在这种情况下作为订阅的解释作为切片的优先级(如果切片列表不包含适当切片的情况)来消除歧义。

切片的语义如下。主要索引(使用与正常订阅相同的 __getitem__() 方法)与从切片列表构造的密钥进行索引,如下所示。如果切片列表包含至少一个逗号,则键是包含切片项目的转换的元组;否则,单独切片项的转换是关键。作为表达式的切片项目的转换是该表达式。适当切片的转换是切片对象(参见节 标准类型层次结构),其 startstopstep 属性是分别作为下界,上界和步幅给出的表达式的值,用 None 代替缺失的表达式。

6.3.4. 呼叫

呼叫呼叫具有可能空的系列 参数 的可呼叫对象(例如,function):

call                 ::=  primary "(" [argument_list [","] | comprehension] ")"
argument_list        ::=  positional_arguments ["," starred_and_keywords]
                            ["," keywords_arguments]
                          | starred_and_keywords ["," keywords_arguments]
                          | keywords_arguments
positional_arguments ::=  ["*"] expression ("," ["*"] expression)*
starred_and_keywords ::=  ("*" expression | keyword_item)
                          ("," "*" expression | "," keyword_item)*
keywords_arguments   ::=  (keyword_item | "**" expression)
                          ("," keyword_item | "**" expression)*
keyword_item         ::=  identifier "=" expression

可选的尾部逗号可以出现在位置和关键字参数之后,但不影响语义。

主体必须求值为可调用对象(用户定义的函数,内置函数,内置对象的方法,类对象,类实例的方法以及具有 __call__() 方法的所有对象都是可调用的)。在尝试调用之前,将评估所有参数表达式。有关正式 parameter 列表的语法,请参见 函数定义 部分。

如果存在关键字参数,则首先将它们转换为位置参数,如下所示。首先,为形式参数创建未填充槽的列表。如果有N个位置参数,它们被放置在前N个槽中。接下来,对于每个关键字参数,标识符用于确定相应的时隙(如果标识符与第一形式参数名称相同,则使用第一时隙,等等)。如果插槽已经填充,则会引发 TypeError 异常。否则,参数的值被放置在槽中,填充它(即使表达式是 None,它填充槽)。处理完所有参数后,仍未填充的插槽将使用函数定义中的相应默认值填充。 (默认值计算一次,当函数被定义时;因此,用作默认值的可变对象,例如列表或字典将被没有指定对应槽的参数值的所有调用共享;这应该通常应该避免。)如果有未指定缺省值的未填充插槽,则会引发 TypeError 异常。否则,填充时隙列表用作呼叫的参数列表。

实现可以提供其位置参数不具有名称的内置函数,即使它们为了文档的目的被“命名”,并且因此不能由关键字提供。在CPython中,在C中实现的函数使用 PyArg_ParseTuple() 来解析它们的参数。

如果存在比形式参数槽更多的位置参数,则产生 TypeError 异常,除非存在使用语法 *identifier 的形式参数;在这种情况下,该形式参数接收包含多余位置参数的元组(或者如果没有多余的位置参数,则为空元组)。

如果任何关键字参数不对应于形式参数名称,则引发 TypeError 异常,除非存在使用语法 **identifier 的形式参数;在这种情况下,该形式参数接收包含多余关键字参数(使用关键字作为键和参数值作为对应值)的字典,或者如果没有多余的关键字参数,则为(新)空字典。

如果语法 *expression 出现在函数调用中,则 expression 必须求值为 iterable。来自这些迭代的元素被视为是额外的位置参数。对于呼叫 f(x1, x2, *y, x3, x4),如果 y 评估为序列 y1,...,yM,则这等效于具有M + 4个位置参数 x1x2y1,...,yMx3x4 的呼叫。

这样做的结果是,虽然 *expression 语法可能出现 after 显式关键字参数,但它被处理为 before 关键字参数(和任何 **expression 参数 - 见下文)。所以:

>>> def f(a, b):
...     print(a, b)
...
>>> f(b=1, *(2,))
2 1
>>> f(a=1, *(2,))
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: f() got multiple values for keyword argument 'a'
>>> f(1, *(2,))
1 2

在同一个调用中使用关键字参数和 *expression 语法是不寻常的,因此在实践中不会出现这种混淆。

如果语法 **expression 出现在函数调用中,则 expression 必须求值为 mapping,其内容被视为附加的关键字参数。如果关键字已经存在(作为显式关键字参数,或者来自另一个解包),则会引发 TypeError 异常。

使用语法 *identifier**identifier 的形式参数不能用作位置参数槽或关键字参数名。

在 3.5 版更改: 函数调用接受任意数量的 *** 解包,位置参数可以跟随可迭代解包(*),并且关键字参数可以遵循字典解包(**)。最初由 PEP 448 提出。

调用总是返回一些值,可能是 None,除非它引发异常。如何计算此值取决于可调用对象的类型。

如果是 - -

用户定义的函数:

函数的代码块被执行,将参数列表传递给它。代码块的第一件事是将形式参数绑定到参数;这在 函数定义 节中有描述。当代码块执行 return 语句时,它指定函数调用的返回值。

内置函数或方法:

结果取决于翻译;有关内置函数和方法的说明,请参阅 内置函数

一个类对象:

返回该类的新实例。

一个类实例方法:

调用相应的用户定义函数,参数列表比调用的参数列表长一个:实例成为第一个参数。

一个类实例:

类必须定义一个 __call__() 方法;那么效果与调用该方法时的效果相同。

6.4. 等待表达

暂停在 awaitable 对象上执行 coroutine。只能在 coroutine function 内使用。

await_expr ::=  "await" primary

3.5 新版功能.

6.5. 电源操作员

幂运算符在其左边比一元运算符绑定更紧密;它绑定不比一元运算符在其右边。语法是:

power ::=  ( await_expr | primary ) ["**" u_expr]

因此,在未加括号的幂和一元运算符序列中,从右到左对算子进行求值(这不限制操作数的求值顺序):-1**2 导致 -1

幂运算符具有与内置 pow() 函数相同的语义,当使用两个参数调用时:它产生其左参数引起其右参数的权力。数值参数首先转换为常用类型,结果为该类型。

对于int操作数,结果具有与操作数相同的类型,除非第二个参数为负;在这种情况下,所有参数都转换为float,并传递float结果。例如,10**2 返回 100,但 10**-2 返回 0.01

0.0 提高到负功率导致 ZeroDivisionError。将负数提高为分数幂会导致 complex 数。 (在早期版本中它提出了 ValueError。)

6.6. 一元运算和按位运算

所有一元运算和按位运算具有相同的优先级:

u_expr ::=  power | "-" u_expr | "+" u_expr | "~" u_expr

一元 - (减)运算符产生其数值参数的否定。

一元 + (加号)运算符产生其数值参数不变。

一元 ~ (反转)运算符产生其整数参数的按位反转。 x 的按位反转被定义为 -(x+1)。它只适用于整数。

在所有这三种情况下,如果参数没有正确的类型,则会引发 TypeError 异常。

6.7. 二进制算术运算

二进制算术运算具有常规的优先级。注意,这些操作中的一些也适用于某些非数字类型。除了幂运算符,只有两个级别,一个用于乘法运算符,一个用于加法运算符:

m_expr ::=  u_expr | m_expr "*" u_expr | m_expr "@" m_expr |
            m_expr "//" u_expr| m_expr "/" u_expr |
            m_expr "%" u_expr
a_expr ::=  m_expr | a_expr "+" m_expr | a_expr "-" m_expr

* (乘法)运算符产生其参数的乘积。参数必须是数字,或者一个参数必须是整数,另一个必须是序列。在前一种情况下,数字被转换为公共类型,然后相乘。在后一种情况下,执行序列重复;负重复因子产生空序列。

@ (at)运算符旨在用于矩阵乘法。没有内置Python类型实现此运算符。

3.5 新版功能.

/ (division)和 // (floor division)运算符产生它们的参数的商。数值参数首先转换为公共类型。整数的除法产生一个浮点,而整数的底除法得到一个整数;结果是应用于结果的’floor’函数的数学除法。除以零会引起 ZeroDivisionError 异常。

% (模)运算符产生第一个参数除以秒的余数。数值参数首先转换为公共类型。零右参数引发 ZeroDivisionError 异常。参数可以是浮点数,例如,3.14%0.7 等于 0.34 (因为 3.14 等于 4*0.7 + 0.34)。模运算符总是产生与其第二操作数(或零)具有相同符号的结果。结果的绝对值严格小于第二操作数 [1] 的绝对值。

底层划分和模运算符通过以下身份连接:x == (x//y)*y + (x%y)。底部划分和模数也与内置函数 divmod()divmod(x, y) == (x//y, x%y) 连接。 [2]

除了对数字执行模运算,% 运算符也被字符串对象重载以执行旧式字符串格式化(也称为插值)。字符串格式化的语法在Python库参考手册中的 printf 样式字符串格式 部分中描述。

底部除法运算符,模运算符和 divmod() 函数没有为复数定义。相反,如果适当,使用 abs() 函数转换为浮点数。

+ (加法)运算符产生其自变量的和。参数必须是数字,或者两者都是相同类型的序列。在前一种情况下,数字被转换为公共类型,然后加在一起。在后一种情况下,连接序列。

- (减法)运算符产生其自变量的差异。数值参数首先转换为公共类型。

6.8. 换档操作

移位操作的优先级低于算术运算:

shift_expr ::=  a_expr | shift_expr ( "<<" | ">>" ) a_expr

这些运算符接受整数作为参数。它们将第一个参数向左或向右移动由第二个参数给出的位数。

n 比特的右移被定义为由 pow(2,n) 进行的floor除法。 n 位的左移被定义为与 pow(2,n) 的乘法。

注解

在当前实现中,右手操作数最多需要 sys.maxsize。如果右手操作数大于 sys.maxsize,则引发 OverflowError 异常。

6.9. 二进制逐位操作

三个逐位操作中的每一个具有不同的优先级:

and_expr ::=  shift_expr | and_expr "&" shift_expr
xor_expr ::=  and_expr | xor_expr "^" and_expr
or_expr  ::=  xor_expr | or_expr "|" xor_expr

& 运算符产生其参数的按位AND,它必须是整数。

^ 运算符产生其参数的按位异或(异或),其必须是整数。

| 运算符产生其参数的按位(包括)OR,它必须是整数。

6.10. 比较

与C不同,Python中的所有比较操作具有相同的优先级,低于任何算术,移位或按位操作的优先级。同样与C不同,像 a < b < c 这样的表达式具有数学中常见的解释:

comparison    ::=  or_expr ( comp_operator or_expr )*
comp_operator ::=  "<" | ">" | "==" | ">=" | "<=" | "!="
                   | "is" ["not"] | ["not"] "in"

比较产生布尔值:TrueFalse

比较可以任意链接,例如,x < y <= z 等效于 x < y and y <= z,除了 y 仅被评估一次(但是在两种情况下,当发现 x < y 为假时,z 根本不被评估)。

形式上,如果 abc,...,yz 是表达式并且 op1op2,...,opN 是比较运算符,则 a op1 b op2 c ... y opN z 等价于 a op1 b and b op2 c and ... y opN z,除了每个表达式被评估最多一次。

注意,a op1 b op2 c 不暗示 ac 之间的任何种类的比较,使得例如 x < y > z 是完全合法的(虽然也许不漂亮)。

6.10.1. 价值比较

运算符 <>==>=<=!= 比较两个对象的值。对象不需要具有相同的类型。

Chapter 对象,值和类型 声明对象有一个值(除了类型和标识)。对象的值在Python中是一个相当抽象的概念:例如,对象的值没有规范的访问方法。此外,不要求对象的值应以特定方式构建,例如,包括所有其数据属性。比较运算符实现了对象的值是什么的特定概念。可以认为它们通过它们的比较实现间接地定义对象的值。

因为所有类型都是(直接或间接) object 的子类型,所以它们继承了来自 object 的默认比较行为。类型可以通过实现 rich comparison methods (如 __lt__()基本定制 中描述的 __lt__())来定制它们的比较行为。

相等比较(==!=)的默认行为基于对象的身份。因此,具有相同身份的实例的等式比较导致相等,并且具有不同身份的实例的等式比较导致不等式。这种默认行为的动机是所有对象应该是反身的(即 x is y 意味着 x == y)的愿望。

不提供默认顺序比较(<><=>=);尝试提高 TypeError。这种默认行为的动机是缺乏与等式相似的不变量。

默认等式比较的行为,具有不同标识的实例总是不相等,可能与需要具有对象值和基于值的等式的敏感定义的类型形成对比。这种类型需要定制它们的比较行为,事实上,一些内置类型已经做到了。

以下列表描述了最重要的内置类型的比较行为。

  • 内置数值类型(数字类型— int,float,complex)和标准库类型 fractions.Fractiondecimal.Decimal 的数量可以在其类型之内和之间进行比较,同时限制复杂数字不支持顺序比较。在所涉及的类型的范围内,它们在数学上(算法上)进行比较而不损失精度。

    非数字值 float('NaN')Decimal('NaN') 是特殊的。它们与自己完全相同(x is x 是真的),但不等于自己(x == x 是假的)。此外,将任何数字与非数字值进行比较将返回 False。例如,3 < float('NaN')float('NaN') < 3 都将返回 False

  • 二元序列(bytesbytearray 的实例)可以在它们的类型之内和之间进行比较。他们使用元素的数值按字典顺序进行比较。

  • 字符串(str 的实例)使用字符的数字Unicode代码点(内置函数 ord() 的结果)按字典比较。 [3]

    字符串和二进制序列不能直接比较。

  • 序列(tuplelistrange 的实例)只能在每种类型中比较,限制范围不支持序列比较。这些类型的平等比较导致不均衡,并且这些类型的排序比较提高了 TypeError

    序列使用相应元素的比较按照字典顺序进行比较,从而强化元素的反射性。

    在强化元素的反身性时,集合的比较假定对于集合元素 xx == x 总是真的。基于该假设,首先比较元素身份,并且仅对不同元素执行元素比较。如果比较的元素是反身性的,则该方法产生与严格元素比较相同的结果。对于非反射元素,结果不同于严格元素比较,并且可能是令人惊讶的:非反射非数值例如导致在列表中使用时的以下比较行为:

    >>> nan = float('NaN')
    >>> nan is nan
    True
    >>> nan == nan
    False                 <-- the defined non-reflexive behavior of NaN
    >>> [nan] == [nan]
    True                  <-- list enforces reflexivity and tests identity first
    

    内置集合之间的词典比较工作如下:

    • 对于两个集合比较相等,它们必须是相同的类型,具有相同的长度,并且每对相应的元素必须比较相等(例如,[1,2] == (1,2) 为假,因为类型不相同)。

    • 支持顺序比较的集合与其第一个不等的元素排序相同(例如,[1,2,x] <= [1,2,y]x <= y 的值相同)。如果对应的元素不存在,则首先对较短的集合排序(例如,[1,2] < [1,2,3] 为真)。

  • 映射(dict 的实例)当且仅当它们具有相等的 (key, value) 对时才比较相等。键和元素的平等比较强化反身性。

    订单比较(<><=>=)提高 TypeError

  • 集合(setfrozenset 的实例)可以在其类型之内和之间进行比较。

    它们将顺序比较运算符定义为子集和超集测试。这些关系不定义总排序(例如,两个集合 {1,2}{2,3} 不相等,也不是彼此的子集,也不是彼此的超集)。因此,集合不是取决于总排序的函数的适当参数(例如,给定作为输入的集合列表,min()max()sorted() 产生未定义的结果)。

    比较集合强制其元素的反身性。

  • 大多数其他内置类型没有实现比较方法,因此它们继承了默认的比较行为。

自定义其比较行为的用户定义类应遵循一些一致性规则,如果可能:

  • 平等比较应该是反思性的。换句话说,相同的对象应该比较相等:

    x is y 意味着 x == y

  • 比较应该是对称的。换句话说,以下表达式应该具有相同的结果:

    x == yy == x

    x != yy != x

    x < yy > x

    x <= yy >= x

  • 比较应该是可传递的。以下(非详尽的)实施例说明:

    x > y and y > z 意味着 x > z

    x < y and y <= z 意味着 x < z

  • 反向比较应该导致布尔否定。换句话说,以下表达式应该具有相同的结果:

    x == ynot x != y

    x < ynot x >= y (用于总排序)

    x > ynot x <= y (用于总排序)

    最后两个表达式适用于完全排序的集合(例如,对序列,但不适用于集合或映射)。另请参阅 total_ordering() 装饰器。

Python不强制执行这些一致性规则。事实上,not-a-number值是不遵循这些规则的示例。

6.10.2. 成员测试操作

运营商 innot in 测试成员资格。如果 xs 的成员,则 x in s 评估为真,否则为假。 x not in s 返回 x in s 的否定。所有内置的序列和集合类型支持这个以及字典,为此 in 测试字典是否具有给定的键。对于诸如list,tuple,set,frozenset,dict或collections.deque的容器类型,表达式 x in y 等价于 any(x is e or x == e for e in y)

对于字符串和字节类型,当且仅当 xy 的子字符串时,x in y 才为真。等效测试是 y.find(x) != -1。空字符串总是被认为是任何其他字符串的子字符串,因此 "" in "abc" 将返回 True

对于定义 __contains__() 方法的用户定义类,如果且仅当 y.__contains__(x) 为真,x in y 才为真。

对于不定义 __contains__() 但确实定义 __iter__() 用户定义的类,如果在遍历 y 时产生一些值 z 具有 x == zx in y 为真。如果在迭代期间引发异常,就好像 in 引发了异常。

最后,尝试旧式迭代协议:如果一个类定义 __getitem__(),当且仅当存在非负整数索引 i 使得 x == y[i] 和所有较低整数索引不引起 IndexError 异常时,x in y 才为真。 (如果引发任何其他异常,就好像 in 引发了异常)。

运算符 not in 被定义为具有 in 的反真实值。

6.10.3. 身份比较

运算符 isis not 测试对象标识:当且仅当 xy 是相同的对象时,x is y 才为真。对象标识使用 id() 函数确定。 x is not y 得到相反的真值。 [4]

6.11. 布尔运算

or_test  ::=  and_test | or_test "or" and_test
and_test ::=  not_test | and_test "and" not_test
not_test ::=  comparison | "not" not_test

在布尔运算的上下文中,以及当控制流语句使用表达式时,以下值被解释为false:FalseNone,所有类型的数字零,以及空字符串和容器(包括字符串,元组,列表, ,集和frozensets)。所有其他值都被解释为true。用户定义的对象可以通过提供 __bool__() 方法来定制它们的真值。

如果其参数为假,运算符 not 产生 True,否则为 False

表达式 x and y 首先评估 x;如果 x 为false,则返回其值;否则,将评估 y 并返回结果值。

表达式 x or y 首先评估 x;如果 x 为true,则返回其值;否则,将评估 y 并返回结果值。

(注意,andor 都不限制它们返回到 FalseTrue 的值和类型,而是返回最后一个求值的参数。这有时是有用的。例如,如果 s 是一个字符串,当它为空时需要被默认值替换,表达式 s or 'foo' 产生需要的值。因为 not 必须创建一个新的值,它返回一个布尔值,而不考虑它的参数类型(例如,not 'foo' 产生 False 而不是 '')。

6.12. 条件表达式

conditional_expression ::=  or_test ["if" or_test "else" expression]
expression             ::=  conditional_expression | lambda_expr
expression_nocond      ::=  or_test | lambda_expr_nocond

条件表达式(有时称为“三元运算符”)具有所有Python操作的最低优先级。

表达式 x if C else y 首先评估条件,C 而不是 x。如果 C 为真,则评估 x 并返回其值;否则,将评估 y 并返回其值。

有关条件表达式的更多详细信息,请参阅 PEP 308

6.13. Lambdas

lambda_expr        ::=  "lambda" [parameter_list]: expression
lambda_expr_nocond ::=  "lambda" [parameter_list]: expression_nocond

Lambda表达式(有时称为lambda表单)用于创建匿名函数。表达式 lambda arguments: expression 产生一个函数对象。未命名的对象的行为就像一个函数对象,定义如下:

def <lambda>(arguments):
    return expression

有关参数列表的语法,请参见 函数定义 部分。请注意,使用lambda表达式创建的函数不能包含语句或注释。

6.14. 表达式列表

expression_list    ::=  expression ( "," expression )* [","]
starred_list       ::=  starred_item ( "," starred_item )* [","]
starred_expression ::=  expression | ( starred_item "," )* [starred_item]
starred_item       ::=  expression | "*" or_expr

除了当列表或集合的一部分显示时,包含至少一个逗号的表达式列表产生一个元组。元组的长度是列表中的表达式数。表达式从左到右计算。

星号 * 表示 iterable unpacking。其操作数必须是 iterable。可迭代扩展为项目序列,其被包括在解包的站点处的新元组,列表或集合中。

3.5 新版功能: 可迭代解包在表达式列表中,最初由 PEP 448 提出。

尾部逗号只需要创建单个元组(a.k.a. a singleton);它在所有其他情况下是可选的。没有尾随逗号的单个表达式不会创建元组,而是生成该表达式的值。 (要创建一个空元组,请使用一对空的括号:()。)

6.15. 评估顺序

Python从左到右评估表达式。注意,在计算赋值时,右侧在左侧之前计算。

在下面几行中,表达式将以其后缀的算术顺序进行计算:

expr1, expr2, expr3, expr4
(expr1, expr2, expr3, expr4)
{expr1: expr2, expr3: expr4}
expr1 + expr2 * (expr3 - expr4)
expr1(expr2, expr3, *expr4, **expr5)
expr3, expr4 = expr1, expr2

6.16. 运算符优先级

下表总结了Python中的运算符优先级,从最低优先级(最低绑定)到最高优先级(最高绑定)。同一框中的运算符具有相同的优先级。除非明确给出语法,否则运算符是二进制的。运算符在同一个盒组中从左到右(除了取幂,从右到左分组)。

请注意,比较,成员资格测试和身份测试都具有相同的优先级,并具有 比较 部分中所述的从左到右的链接特性。

操作员

描述

lambda

Lambda表达式

if - else

条件表达式

or

布尔OR

and

布尔AND

not x

布尔NOT

innot inisis not<<=>>=!===

比较,包括成员资格测试和身份测试

|

按位或

^

按位异或

&

按位AND

<<>>

转变

+-

加减

*@///%

乘法,矩阵乘法除法,余数 [5]

+x-x~x

正,负,按位NOT

**

指数 [6]

await x

等待表达

x[index]x[index:index]x(arguments...)x.attribute

订阅,切片,调用,属性引用

(expressions...)[expressions...]{key: value...}{expressions...}

绑定或元组显示,列表显示,字典显示,设置显示

脚注

[1]

虽然 abs(x%y) < abs(y) 在数学上是真实的,但对于浮点,由于四舍五入,它可能不是数值真的。例如,假设一个Python浮点数为IEEE 754双精度数的平台,为了使 -1e-100 % 1e1001e100 具有相同的符号,计算结果为 -1e-100 + 1e100,其在数值上完全等于 1e100。函数 math.fmod() 返回一个结果,其符号与第一个参数的符号相匹配,因此在这种情况下返回 -1e-100。哪种方法更合适取决于应用程序。

[2]

如果x非常接近y的确切整数倍,则由于四舍五入,x//y 可能比 (x-x%y)//y 大一。在这种情况下,Python返回后一个结果,以保持 divmod(x,y)[0] * y + x % y 非常接近 x

[3]

Unicode标准区分 code points (例如U + 0041)和 abstract characters (例如“LATIN CAPITAL LETTER A”)。虽然Unicode中的大多数抽象字符仅使用一个代码点来表示,但是存在可以使用多于一个代码点的序列来表示的多个抽象字符。例如,抽象字符“LATIN CAPITAL LETTER C WITH CEDILLA”可以表示为在代码位置U + 00C7处的单个 precomposed character,或者作为在代码位置U + 0043(拉丁资本字母C)处的 base character 的序列,之后是代码位置U + 0327处的 combining character (COMBINING CEDILLA)。

字符串上的比较运算符在Unicode代码点级别进行比较。这可能对人类是反直觉的。例如,"\u00C7" == "\u0043\u0327"False,即使两个字符串表示相同的抽象字符“LATIN CAPITAL LETTER C WITH CEDILLA”。

要在抽象字符级别(即,以对人类直观的方式)比较字符串,请使用 unicodedata.normalize()

[4]

由于自动垃圾回收,自由列表和描述符的动态特性,您可能会注意到在某些 is 操作符使用中看起来不寻常的行为,比如涉及实例方法或常量之间的比较。检查他们的文档了解更多信息。

[5]

% 操作符也用于字符串格式化;相同的优先级适用。

[6]

幂运算符 ** 在其右边比算术或按位一元运算符绑定不紧密,即 2**-10.5