6.表达式

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

语法注释:在本章和后续章节中,扩展的BNF表示法将用于描述语法,而不是词法分析。当(一种替代)语法规则具有表单时

name

:: =  othername

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

 

6.1。算术转换

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

  • 如果任一参数是复数,则另一个参数转换为复数;
  • 否则,如果任一参数是浮点数,则另一个转换为浮点数;
  • 否则,两者必须是整数,不需要转换。

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

 

6.2。原子

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

atom 
 :: =
identifier
|
literal
|
enclosure
 :: = | | |  | |
enclosure
 
 
parenth_formlist_displaydict_displayset_displaygenerator_expressionyield_atom

 

 

6.2.1。标识符(名称)

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

当名称绑定到对象时,对atom的评估会产生该对象。如果未绑定名称,则尝试对其进行评估会引发NameError 异常。

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

 

6.2.2。文字

Python支持字符串和字节文字以及各种数字文字:

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

 

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

所有文字都对应于不可变数据类型,因此对象的标识不如其值重要。对具有相同值的文字的多次评估(在程序文本中出现相同或不同的出现)可以获得具有相同值的相同对象或不同对象。

 

6.2.3。带括号的表格

带括号的表单是括在括号中的可选表达式列表

parenth_form
 :: =“(”[
starred_expression
]“)”

 

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

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

请注意,元组不是由括号组成,而是使用逗号运算符。唯一的例外是空元组, 需要括号- 在表达式中允许不带括号 “无”会导致含糊不清并允许常见错别字传递未被捕获。

 

6.2.4。显示列表,集和词典

为了构造一个列表,一个集合或一个字典,Python提供了一种称为“显示”的特殊语法,每种语法都有两种形式:

  • 容器内容是明确列出的,或者
  • 它们是通过一组循环和过滤指令计算出来的,称为 理解

理解的常见语法元素是:

comprehension
 :: =
comp_for 
 :: = [“async”]“for” “in” [ ]
comp_iter 
 :: =   |
comp_if 
 :: =“if” [ ]
expression
 
comp_for
 
 
target_listor_testcomp_itercomp_forcomp_if
 
expression_nocondcomp_iter

 

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

但是,除了最左边的for子句中的iterable表达式之外,理解还在一个单独的隐式嵌套作用域中执行。这可确保分配给目标列表中的名称不会“泄漏”到封闭范围中。

最左边for子句中的可迭代表达式直接在封闭范围内计算,然后作为参数传递给隐含嵌套范围。最后一个for子句中的后续子句和任何过滤条件for无法在封闭范围内进行求值,因为它们可能取决于从最左边的可迭代获得的值。例如: 。[x*y for x in range(10) for y in range(x, x+10)]

为了确保理解总是产生适当类型的容器,yield并且在隐式嵌套范围内禁止表达式(在Python 3.7中,这样的表达式 在编译时发出,在Python 3.8+中它们将发出)。yield fromDeprecationWarningSyntaxError

从Python 3.6开始,在函数中, 可以使用子句来迭代异步迭代器。函数中的理解可以包括在前导表达式后面的a 或子句,可以包含附加或 子句,也可以使用表达式。如果理解包含子句或表达式,则称为 异步理解。异步理解可以暂停其出现的协程函数的执行。也可以看看async defasync forasync defforasync forforasync forawaitasyncforawaitPEP 530

版本3.6中的新功能:引入了异步理解。

自从3.7版本不推荐使用:yield与在隐含嵌套范围弃用。yield from

 

6.2.5。列表显示

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

list_display
 :: =“[”[
starred_list
|
comprehension
]“]”

 

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

 

6.2.6。设定显示

集合显示用花括号表示,并且由于缺少分隔键和值的冒号而与字典显示区分开来:

set_display
 :: =“{”(
starred_list
|
comprehension
)“}”

 

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

无法构造空集{}; 这个文字构造了一个空字典。

 

6.2.7。字典显示

字典显示是用花括号括起来的可能为空的一系列键/数据对:

dict_display 
 :: =“{”[
key_datum_list
|
dict_comprehension
]“}”
key_datum_list 
 :: =
key_datum
(“,”
key_datum
)* [“,”]
key_datum 
 :: =
expression
“:”
expression
| “**”
dict_comprehension
 :: = “:”
or_expr
 
 
expressionexpression

 

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

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

双星号**表示字典解包。它的操作数必须是映射。每个映射项都添加到新字典中。后面的值替换先前由键/数据对和早期字典解包设置的值。

版本3.5中的新功能:解压缩到最初由…提出的字典显示中PEP 448

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

前面的标准类型层次结构一节中列出了对键值类型的限制 。(总而言之,密钥类型应该是可清除的,它排除了所有可变对象。)未检测到重复密钥之间的冲突; 为给定键值存储的最后一个数据(文本上最右边的显示)占优势。

 

6.2.8。生成器表达式

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

generator_expression
 :: =“(” “)”
expression

 


comp_for生成器表达式生成一个新的生成器对象。它的语法与理解相同,只是它括在括号中而不是括号或花括号中。

__next__()为生成器对象调用该方法时,与生成器表达式中使用的变量会被懒惰地评估 (与普通生成器一样)。但是,for会立即计算最左边子句中的可迭代表达式,以便在定义生成器表达式的位置发出由它产生的错误,而不是在检索第一个值的位置发出。最后一个for子句中的后续子句和任何过滤条件 for无法在封闭范围内进行求值,因为它们可能取决于从最左边的可迭代获得的值。例如: 。(x*y for x in range(10) for y inrange(x, x+10))

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

为了避免干扰生成器表达式本身的预期操作,yield并且在隐式定义的生成器中禁止表达式(在Python 3.7中,这样的表达式在编译时发出 ,在Python 3.8+中它们将发出 )。yield fromDeprecationWarningSyntaxError

如果生成器表达式包含 子句或表达式,则称为 异步生成器表达式异步生成器表达式返回一个新的异步生成器对象,它是一个异步迭代器(请参阅异步迭代器)。async forawait

版本3.6中的新功能:引入了异步生成器表达式。

在3.7版中更改:在Python 3.7之前,异步生成器表达式只能出现在协同程序中。从3.7开始,任何函数都可以使用异步生成器表达式。async def

自从3.7版本不推荐使用:yield与在隐含嵌套范围弃用。yield from

 

6.2.9。收益表达式

yield_atom 
 :: =“(”
yield_expression
“)”
yield_expression
 :: =“yield”[
expression_list
| “从”
expression
]

 

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

def gen(): 
    # defines a generator function 
    yield 123 
async def agen(): 
    # defines an asynchronous generator function 
    yield 123

 

由于它们对包含范围的副作用,yield表达式不允许作为用于实现理解和生成器表达式的隐式定义的范围的一部分(在Python 3.7中,这样的表达式DeprecationWarning在编译时发出,在Python 3.8+中它们将发出SyntaxError)。

从版本3.7开始不推荐使用:在用于实现理解和生成器表达式的隐式嵌套范围中不推荐使用Yield表达式。

发电机功能在下面描述的,当异步发电机功能将在节分别描述 异步发电机的功能

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

所有这些使得生成器功能与协同程序非常相似; 它们产生多次,它们有多个入口点并且它们的执行可以被暂停。唯一的区别是生成器函数无法控制执行后应该继续执行的位置; 控制器总是转移到发电机的呼叫者。

try构造中的任何位置都允许使用yield表达式。如果生成器在最终确定之前没有恢复(通过达到零引用计数或通过垃圾收集),close()将调用generator-iterator的方法,允许finally执行任何挂起的子句。

当被使用时,它把所供应的表达式作为subiterator。该子转换器生成的所有值都直接传递给当前生成器方法的调用者。传入的任何值和传入的 任何异常都会传递 给底层迭代器(如果它具有适当的方法)。如果不是这种情况, 则会提高或者,而 只是立即提高传递的异常。yield from<expr>send()throw()send()AttributeErrorTypeErrorthrow()

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

版本3.3中已更改:已添加为将控制流委派给子订户。yield from <expr>

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

也可以看看

PEP 255 – 简单的发电机
yield向Python 添加生成器和语句的提议。
PEP 342 – 通过增强型发电机的协同程序
建议增强生成器的API和语法,使它们可用作简单的协同程序。
PEP 380 – 委托给子发电机的语法
提出了引入yield_from语法的建议,使得子代的生成变得容易。
PEP 525 – 异步发电机
扩大的提案 PEP 492通过向协同程序功能添加生成器功能。

 

6.2.9.1。生成器 – 迭代器方法

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

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

 

generator.__next__
开始执行生成器函数或在最后执行的yield表达式中恢复它。当使用__next__()方法恢复生成器函数时 ,当前yield表达式始终求值为None。然后执行继续到下一个yield表达式,再次暂停生成器,并将值 expression_list返回给__next__()调用者。如果生成器退出而不产生另一个值,StopIteration 则会引发异常。

此方法通常是隐式调用的,例如通过for循环或内置next()函数调用。

generator.send
恢复执行并将值“发送”到生成器函数中。所述 参数成为当前产量表达的结果。该 send()方法返回由生成器产生的下一个值,或者StopIteration如果生成器退出而不产生另一个值则引发。当send()调用启动生成器时,必须将其None作为参数调用,因为没有可以接收该值的yield表达式。
generator.throw类型[[追溯
type在生成器暂停时引发类型异常,并返回生成器函数产生的下一个值。如果生成器退出而不产生另一个值,StopIteration则会引发异常。如果生成器函数没有捕获传入的异常,或者引发另一个异常,那么该异常会传播给调用者。

 

generator.close
GeneratorExit在生成器功能暂停时提高a 。如果生成器函数然后正常退出,已经关闭或者引发GeneratorExit(通过不捕获异常),则关闭返回其调用者。如果生成器产生一个值, RuntimeError则引发a。如果生成器引发任何其他异常,它将传播给调用者。 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.

 

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

 

6.2.9.3。异步生成器函数

在使用进一步定义的函数或方法中存在yield表达式将该函数 定义为 异步成器函数。async def

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

调用其中一个异步生成器的方法会返回一个 等待对象,并在等待该对象时开始执行。那时,执行进入第一个yield表达式,再次暂停,返回值 expression_list到了等待的协程。与生成器一样,暂停意味着保留所有本地状态,包括局部变量的当前绑定,指令指针,内部评估堆栈以及任何异常处理的状态。当通过等待异步生成器的方法返回的下一个对象来恢复执行时,该函数可以继续进行,就像yield表达式只是另一个外部调用一样。恢复后yield表达式的值取决于恢复执行的方法。如果 __anext__()使用,那么结果是None。否则,如果asend()使用if ,则结果将是传递给该方法的值。

在异步生成器函数中,允许yield表达式在try构造中的任何位置。但是,如果异步生成器在完成之前未恢复(通过达到零引用计数或通过垃圾回收),则try 构造中的yield表达式可能导致无法执行pending finally 子句。在这种情况下,运行异步生成器的事件循环或调度程序负责调用异步生成器 – 迭代器aclose()方法并运行生成的协同程序对象,从而允许finally执行任何挂起的子句。

为了完成最终化,事件循环应该定义一个终结器函数,它接受一个异步生成器迭代器,并可能调用aclose()并执行协程。可以通过调用来注册该 终结sys.set_asyncgen_hooks()。首次迭代时,异步生成器迭代器将存储在完成时调用的已注册终结器。对于一个的参考例终结方法见实施 asyncio.Loop.shutdown_asyncgens在LIB / ASYNCIO / base_events.py。

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

 

6.2.9.4。异步生成器 – 迭代器方法

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

 

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

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

coroutine agen.asend
返回一个等待的,当运行时恢复异步生成器的执行。与send()生成器的方法一样,这会将值“发送”到异步生成器函数中,并且value参数将成为当前yield表达式的结果。asend()方法返回的等待将返回由生成器产生的下一个值作为StopIterationraise 的值 ,或者StopAsyncIteration如果异步生成器退出而不产生另一个值则引发。当 asend()调用它来启动异步生成器时,必须将其None作为参数调用,因为没有可以接收该值的yield表达式。
coroutine agen.athrowtype [value [traceback 
返回一个等待,type它在异步生成器暂停时引发类型异常,并返回生成器函数产生的下一个值作为引发StopIteration异常的值 。如果异步生成器退出而没有产生另一个值,StopAsyncIteration则等待引发异常。如果生成器函数没有捕获传入的异常,或者引发另一个异常,那么当等待运行时,该异常会传播给等待的调用者。

 

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

 

6.3。初学者

Primaries代表语言最紧密的操作。他们的语法是:

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

 

 

6.3.1。属性引用

属性引用是主要的,后跟句点和名称:

attributeref
 :: =   
primary
“。”
identifier

 

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

 

6.3.2。订阅

 

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

subscription
 :: =   
primary
“[” 
expression_list
“]”

 

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

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

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

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

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

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

 

6.3.3。切片

 

切片选择序列对象中的一系列项(例如,字符串,元组或列表)。切片可以用作表达式或作为赋值或del语句中的目标 。切片的语法:

切片

:: =   
primary
“[” 
slice_list
“]” 
slice_list 
 :: = 
slice_item
(“,” 
slice_item
)* [“,”] 
slice_item 
 :: = 
expression
| 
proper_slice
 :: = [ ]“:”[ ] [“:”[ ]] 
lower_bound
 :: = 
upper_bound
 :: = 
stride 
 :: = 
proper_slice
 
 
lower_boundupper_boundstrideexpression
expression

 


expression这里的形式语法存在歧义:看起来像表达式列表的任何内容也看起来像切片列表,因此任何订阅都可以解释为切片。不是进一步使语法复杂化,而是通过定义在这种情况下作为预订的解释优先于解释作为切片(如果切片列表不包含适当切片的情况),则消除歧义。

切片的语义如下。使用__getitem__()从切片列表构造的密钥对主数据库进行索引(使用与正常预订相同的方法),如下所示。如果切片列表包含至少一个逗号,则该键是包含切片项的转换的元组; 否则,单个切片项的转换是关键。作为表达式的切片项的转换是该表达式。一个适当的切片的转化是一个切片对象(参见标准类型层次结构),其start, stop并且step属性是给定为分别下限,上限和步幅,所述表达式的值,用None缺少的表达式。

 

6.3.4。电话

调用使用可能为空的参数系列调用可调用对象(例如,函数):

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

 

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

主要必须评估可调用对象(用户定义的函数,内置函数,内置对象的方法,类对象,类实例的方法,以及具有__call__()方法的所有对象都是可调用的)。在尝试调用之前评估所有参数表达式。有关形式参数列表的语法,请参阅函数定义一节。

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

CPython实现细节:实现可能提供内置函数,其位置参数没有名称,即使它们为了文档的目的而“命名”,因此也不能通过关键字提供。在CPython中,这是用于在C中实现的PyArg_ParseTuple()用于解析其参数的函数的情况。

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

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

如果语法*expression出现在函数调用中,则expression必须求值为iterable。来自这些迭代的元素被视为它们是附加的位置参数。对于调用 ,如果y计算到序列y1,…,yM,这相当于具有M + 4个位置参数x1x2, y1,…,yMx3x4的调用。f(x1, x2, *y, x3, x4)

这样做的结果是虽然*expression语法可能出现 显式关键字参数之后,但它会关键字参数(以及任何**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 <module>
TypeError: f() got multiple values for keyword argument 'a'
>>> f(1, *(2,))
1 2

 

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

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

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

改变在3.5版本中:函数调用接受任何数量***unpackings,定位参数可遵循迭代unpackings( *)和关键字参数可以遵循字典unpackings( **)。最初提出的PEP 448

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

如果是-

用户定义的函数:

执行函数的代码块,并将参数列表传递给它。代码块首先要做的是将形式参数绑定到参数; 这在功能定义一节中描述。当代码块执行return语句时,它指定函数调用的返回值。

内置函数或方法:

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

一个类对象:

返回该类的新实例。

一个类实例方法:

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

一个类实例:

该类必须定义一个__call__()方法; 效果就像调用该方法一样。

 

6.4。等待表达式

在一个等待的对象上暂停执行coroutine。只能在协同程序功能中使用

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到负功率导致a 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
“%” 
a_expr
 :: = | “+” | “ - ”
u_expr
 
 
m_expra_exprm_expra_exprm_expr

 

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

@(在)操作者意图被用于矩阵乘法。没有内置的Python类型实现此运算符

版本3.5中的新功能。

/(部门)和//(楼科)运营商获得他们的论据商。数字参数首先转换为通用类型。整数除法产生浮点数,而整数除法得到整数; 结果是数学除法的结果,“floor”函数应用于结果。除以零会引发ZeroDivisionError 异常。

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

楼层划分和模运算符通过以下标识连接:。楼层划分和模数也与内置功能相连:。[2]。x == (x//y)*y +(x%y)divmod()divmod(x, y) == (x//y, x%y)

除了对数字执行模运算之外,%运算符还会被字符串对象重载以执行旧式字符串格式化(也称为插值)。字符串格式的语法在Python Library Reference,printf-style String Formatting部分中描述。

楼层除法运算符,模运算符和divmod() 函数未定义复数。相反,abs()如果合适,使用该函数转换为浮点数。

+(加)运算符生成它的参数的总和。参数必须都是数字或两者都是相同类型的序列。在前一种情况下,数字被转换为通用类型,然后一起添加。在后一种情况下,序列是连接的。

-(减法)运算符生成它的参数的差异。数字参数首先转换为通用类型。

 

6.8。转移操作

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

shift_expr
 :: =   
a_expr
| 
shift_expr
(“<<”|“>>”)

 

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

右移n位被定义为平分除pow(2,n)。左移n位被定义为乘以pow(2,n)

 

6.9。二进制按位运算

三个按位运算中的每一个都具有不同的优先级

and_expr
 :: =   
shift_expr
| 
and_expr
“&” 
xor_expr
 :: = | “^” 
or_expr
 :: = | “|”
shift_expr
 
 
and_exprxor_exprand_expr
 
xor_expror_exprxor_expr

 

&运营商产生的位与它的参数,它必须是整数。

^运营商产生它的参数,它必须是整数,按位XOR(异或)。

|运营商产生了按位(含)以上的它的参数,它必须是整数。

 

6.10。比较

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

comparison 
 :: =   
or_expr
()* 
comp_operator
 :: =“<”| “>”| “==”| “> =”| “<=”| “!=”
comp_operator
 
or_expr

 

 | “是”[“不是”] | [“not”]“in”

比较产生布尔值:TrueFalse

比较可以任意链接,例如,等同于 ,除了仅评估一次(但在两种情况下都没有被评估,当发现是假的时)。x < y<= zx < y and y <= zyzx < y

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

注意,这并不意味着a和 c之间任何比较,因此,例如,完全合法(尽管可能不是很漂亮)。a op1 b op2 cx <y > z

6.10.1。价值比较

运营商<>==>=<=,和!=比较两个对象的值。对象不需要具有相同的类型。

章节对象,值和类型表明对象具有值(除了类型和标识)。对象的值在Python中是一个相当抽象的概念:例如,对象的值没有规范的访问方法。此外,不要求对象的值应以特定方式构造,例如由其所有数据属性组成。比较运算符实现了对象值的特定概念。人们可以将它们视为通过比较实现间接定义对象的价值。

由于所有类型都是(直接或间接)子类型object,因此它们继承了默认的比较行为object。类型可以通过实现定制自己的行为比较 丰富的比较方法一样__lt__(),在描述 基本的定制

相等性比较(==!=)的默认行为基于对象的标识。因此,具有相同身份的实例的相等比较导致相等,并且具有不同身份的实例的相等性比较导致不等式。这种默认行为的动机是希望所有对象都应该是反身的(即 暗示)。xis yx == y

默认顺序的比较(<><=,和>=)不设置; 企图加油TypeError。这种默认行为的动机是缺乏与平等相似的不变量。

默认相等比较的行为,即具有不同身份的实例总是不相等的,可能与需要具有合理定义的对象值和基于值的相等性的类型形成对比。这些类型需要定制它们的比较行为,事实上,许多内置类型已经完成了。

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

  • 内置数值类型(数字类型 – int,float,complex)和标准库类型的数量fractions.Fractiondecimal.Decimal可以在其类型内部和跨类型进行比较,但复数不支持顺序比较。在所涉及类型的范围内,它们在数学上(算法上)正确地进行比较而不会损失精度。

    非数字值float('NaN')并且decimal.Decimal('NaN')是特殊的。数字与非数字值的任何有序比较都是错误的。反直觉的含义是非数值不等于它们自身。例如,如果,,,,全是假的。此行为符合IEEE 754。x =float('NaN')3 < xx < 3x == xx != x

  • 可以在其类型内和跨类型比较二进制序列(bytes或的实例bytearray)。它们使用元素的数值按字典顺​​序进行比较。

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

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

  • 序列(的实例tuplelistrange)可以仅在每个它们的类型进行比较,与该范围不支持次序比较的限制。这些类型之间的相等比较会导致不平等,并且这些类型之间的排序比较会提高 TypeError

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

    在强制元素的反身性时,集合的比较假定对于集合元素x,始终为真。基于该假设,首先比较元素标识,并且仅针对不同元素执行元素比较。如果比较的元素是自反的,那么这种方法产生与严格元素比较相同的结果。对于非自反元素,结果与严格元素比较的结果不同,并且可能会令人惊讶:例如,非自反的非数字值在列表中使用时会产生以下比较行为:x == 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

     

    内置集合之间的字典比较如下:

    • 对于要比较的两个集合相等,它们必须是相同的类型,具有相同的长度,并且每对相应的元素必须比较相等(例如,因为类型不相同,所以为false)。[1,2] == (1,2)
    • 支持订单比较的集合的排序与它们的第一个不相等的元素相同(例如,具有相同的值)。如果不存在相应的元素,则首先排序较短的集合(例如,为真)。[1,2,x] <= [1,2,y]x <= y[1,2] < [1,2,3]
  • dict当且仅当它们具有相等(键,值)对时映射(实例)才相等。键和值的相等比较强制实现反身性。

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

  • 可以在其类型内和跨类型比较集(set或的实例frozenset)。

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

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

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

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

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

    x is y 暗示 x == y

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

    x == y 和 y == x

    x != y 和 y != x

    x < y 和 y > x

    x <= y 和 y >= x

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

    x > y and y > z 暗示 x > z

    x < y and y <= z 暗示 x < z

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

    x == y 和 not x != y

    x < y和(总排序)not x >= y

    x > y和(总排序)not x <= y

    最后两个表达式适用于完全有序的集合(例如,序列,但不适用于集合或映射)。另见 total_ordering()装饰者。

  • hash()结果应该是平等一致的。相等的对象应具有相同的哈希值,或者标记为不可用。

Python不强制执行这些一致性规则。实际上,非数字值是不遵循这些规则的示例。

 

6.10.2。成员资格测试操作

运营商in和会员资格测试。 计算结果为,如果X是一个成员小号,和其它。 回归否定。所有内置序列和集合类型都支持这个以及字典,其中测试字典是否具有给定键。对于容器类型,例如list,tuple,set,frozenset,dict或collections.deque,表达式等效于。not inx in sTrueFalsex not in sx in sinx in yany(x is e or x == efor e in y)

对于字符串和字节的类型,是当且仅当X是的一个子ÿ。等效测试是。空字符串始终被视为任何其他字符串的子字符串,因此将返回。x in yTruey.find(x) != -1"" in "abc"True

对于定义__contains__()方法的用户定义类,返回if 返回true值,否则返回true 。x inyTruey.__contains__(x)False

对于不定义用户定义的类__contains__(),但不限定 __iter__(),是,如果某个值与同时迭代产生。如果在迭代期间引发异常,则就好像引发了异常一样。x in yTruezx == zyin

最后,旧式迭代协议尝试:如果一个类定义 __getitem__(),是当且仅当有一个非负整数索引这样说,并且所有的整数索引不提高例外。(如果引发任何其他异常,就好像提出异常一样)。x in yTruex == y[i]IndexErrorin

运算符被定义为具有倒数真值 。not inin

 

6.10.3。身份比较

运算符is和对象标识测试:当且仅当xy是同一个对象时才是真的。使用该函数确定对象标识。 产生反向真值。[4]is notx is yid()x is not y

 

6.11。布尔运算

or_test
 :: =   
and_test
| 
or_test
“或” 
and_test
 :: = | “和” 
not_test
 :: = | “不”
and_test
not_testand_testnot_test
 
comparisonnot_test

 


 

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

如果运算符的参数为false, 则运算符not产生。TrueFalse

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

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

需要注意的是既不and也不or限制他们返回的值和类型FalseTrue,而是返回最后一个变量。这有时是有用的,例如,如果s是一个字符串,如果它是空的,应该用默认值替换,表达式产生所需的值。因为必须创建一个新值,所以无论其参数的类型如何,它都会返回一个布尔值(例如,生成而不是。)s or 'foo'notnot 'foo'False''

 

6.12。条件表达式

conditional_expression
 :: =   
or_test
[“if” 
or_test
“else” 
expression
] 
expression 
 :: = 
conditional_expression
| 
expression_nocond 
 :: = |
lambda_expr
 
 
or_testlambda_expr_nocond

 

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

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

看到 PEP 308了解有关条件表达式的更多详细信息。

 

6.13。Lambda表达式

lambda_expr 
 :: =“lambda”[ 
parameter_list
]“:” 
lambda_expr_nocond
 :: =“lambda”[ ]“:”
expression
 
 
parameter_listexpression_nocond

 

Lambda表达式(有时称为lambda表单)用于创建匿名函数。表达式产生一个函数对象。未命名的对象的行为类似于使用以下定义的函数对象:

lambda parameters: expression
def <lambda>(parameters):
    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

 

除非列表或集合显示的一部分,否则包含至少一个逗号的表达式列表会产生元组。元组的长度是列表中表达式的数量。表达式从左到右进行评估。

星号*表示可迭代的解包。它的操作数必须是可迭代的。迭代被扩展为一系列项目,这些项目包含在解包的站点的新元组,列表或集合中。

版本3.5中的新功能:表达式列表中的可迭代解包,最初由提议PEP 448

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

 

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
in,, ,,, ,,,,not inisis not<<=>>=!=== 比较,包括成员资格测试和身份测试
| 按位OR
^ 按位异或
& 按位AND
<<, >> 转移
+, - 加减
*@///% 乘法,矩阵乘法,除法,分区,余数[5]
+x-x~x 正,负,按位NOT
** 指数[6]
await x 等待表达
x[index]x[index:index], x(arguments...)x.attribute 订阅,切片,调用,属性引用
(expressions...), [expressions...], , {key:value...}{expressions...} 绑定或元组显示,列表显示,字典显示,设置显示

脚注

[1] 虽然在数学上是正确的,但对于浮点数而言,由于舍入而在数字上可能不是真的。例如,假设Python浮点数是IEEE 754双精度数的平台,为了具有相同的符号,计算结果在数值上完全等于。该函数 返回一个结果,其符号与第一个参数的符号匹配,因此在这种情况下返回。哪种方法更合适取决于应用程序。abs(x%y) < abs(y)-1e-100 % 1e1001e100-1e-100 + 1e1001e100math.fmod()-1e-100
[2] 如果x非常接近y的精确整数倍,则可能 x//y(x-x%y)//y舍入更大。在这种情况下,Python返回后一个结果,以保持 非常接近。divmod(x,y)[0] * y + x % yx
[3]

Unicode标准区分代码点 (例如U + 0041)和抽象字符(例如“LATIN CAPITAL LETTER A”)。虽然Unicode中的大多数抽象字符仅使用一个代码点来表示,但是还有许多抽象字符可以使用多个代码点的序列来表示。例如,抽象字符“带有CEDILLA的LATIN CAPITAL LETTER C”可以表示为代码位置U + 00C7处的单个合成字符,或者代码位置U + 0043(LATIN CAPITAL LETTER C)处的基本字符序列,然后是代码位置U + 0327(COMBINING CEDILLA)的组合字符

字符串上的比较运算符在Unicode代码点的级别进行比较。这可能与人类相反。例如, 是,即使两个字符串表示相同的抽象性“拉丁大写字母C带下加符”。"\u00C7" == "\u0043\u0327"False

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

[4] 由于自动垃圾收集,空闲列表和描述符的动态特性,您可能会注意到is操作符的某些使用中看似异常的行为,例如涉及实例方法或常量之间的比较。查看他们的文档了解更多信息。
[5] %运营商还用于字符串格式化; 同样的优先权适用。
[6] 幂运算符**结合不同于在其右侧的算术或按位一元运算符较不紧密,也就是2**-10.5