Python表达式

在Python中,表达式是由操作数、运算符和函数调用等组成的语法结构,可以进行各种数学运算、逻辑判断、字符串操作等。本教程将解释 Python 中组成表达式的各种元素的的含义,包括算术转换、幂运算符等等。

语法注释:接下来会使用扩展 BNF 标注来描述语法而不是词法分析。 当(某种替代的)语法规则具有如下形式:

name ::= othername

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

一、算术转换

当对下述某个算术运算符的描述中使用了“数值参数被转换为普通类型”这样的说法,这意味着内置类型的运算符实现采用了如下运作方式:

  • 如果任一参数为复数,另一参数会被转换为复数;
  • 否则,如果任一参数为浮点数,另一参数会被转换为浮点数;
  • 否则,两者应该都为整数,不需要进行转换。

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

二、原子

参见《Python原子》。

三、原型

参见《Python原型》。

四、await表达式

挂起 coroutine 的执行以等待一个 awaitable 对象,只能在 coroutine function 内部使用。例如:

await_expr ::= "await" primary

五、幂运算符

幂运算符的绑定比在其左侧的一元运算符更紧密;但绑定紧密程度不及在其右侧的一元运算符。 句法如下:

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。)

此运算符可使用特殊的 __pow__() 方法来自定义。

六、一元算术和位运算

所有算术和位运算具有相同的优先级:

u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr
  • 一元的 - (负值) 运算符会产生其数字参数的负值;该运算可通过 __neg__() 特殊方法来重载;
  • 一元的 + (正值) 运算符会原样输出其数字参数;该运算可通过 __pos__() 特殊方法来重载;
  • 一元的 ~ (取反) 运算符会对其整数参数按位取反。 x 的按位取反被定义为 -(x+1)。 它只作用于整数或是重载了 __invert__() 特殊方法的自定义对象。

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

七、 二元算术运算符

二元算术运算符遵循传统的优先级。 请注意某些此类运算符也作用于特定的非数字类型。 除幂运算符以外只有两个优先级别,一个作用于乘法型运算符,另一个作用于加法型运算符:

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
  • 运算符 * (乘) 将输出其参数的乘积。 两个参数或者必须都为数字,或者一个参数必须为整数而另一个参数必须为序列,在前一种情况下,两个数字将被转换为相同类型然后相乘; 在后一种情况下,将执行序列的重复;重复因子为负数将输出空序列。

此运算可使用特殊的 __mul__() 和 __rmul__() 方法来自定义,运算符 @ (at) 的目标是用于矩阵乘法;没有内置 Python 类型实现此运算符。

  • 运算符 / (除) 和 // (整除) 将输出其参数的商。 两个数字参数将先被转换为相同类型。 整数相除会输出一个 float 值,整数相整除的结果仍是整数;整除的结果就是使用 'floor' 函数进行算术除法的结果。 除以零的运算将引发 ZeroDivisionError 异常。此运行可使用特殊的 __truediv__() 和 __floordiv__() 方法来自定义。
  • 运算符 % (模) 将输出第一个参数除以第二个参数的余数。 两个数字参数将先被转换为相同类型。 右参数为零将引发 ZeroDivisionError 异常。 参数可以为浮点数,例如 3.14%0.7 等于 0.34 (因为 3.14 等于 4*0.7 + 0.34)。 模运算符的结果的正负总是与第二个操作数一致(或是为零);结果的绝对值一定小于第二个操作数的绝对值。

整除与模运算符的联系可通过以下等式说明: x == (x//y)*y + (x%y)。 此外整除与模也可通过内置函数 divmod() 来同时进行: divmod(x, y) == (x//y, x%y)。

除了对数字执行模运算,运算符 % 还被字符串对象重载用于执行旧式的字符串格式化(又称插值)。 取余运算可使用特殊的 __mod__() 方法来自定义。

整除运算符,模运算符和 divmod() 函数未被定义用于复数。 如果有必要可以使用 abs() 函数将其转换为浮点数。

  • 运算符 + (addition) 将输出其参数的和。 两个参数或者必须都为数字,或者都为相同类型的序列。 在前一种情况下,两个数字将被转换为相同类型然后相加。 在后一种情况下,将执行序列拼接操作。此运算可使用特殊的 __add__() 和 __radd__() 方法来自定义。
  • 运算符 - (减) 将输出其参数的差。 两个数字参数将先被转换为相同类型。此运算可使用特殊的 __sub__() 方法来自定义。

八、移位运算

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

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

这些运算符接受整数参数。 它们会将第一个参数左移或右移第二个参数所指定的比特位数。此运算可使用特殊的 __lshift__() 和 __rshift__() 方法来自定义。右移 n 位被定义为被 pow(2,n) 整除。 左移 n 位被定义为乘以 pow(2,n)。

九、二元位运算

三种位运算具有各不相同的优先级:

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,参数必须都为整数或者其中之一必须为重载了 __and__() 或 __rand__() 特殊方法的自定义对象;
  • ^ 运算符会对其参数执行按位 XOR (异 OR),参数必须都为整数或者其中之一必须为重载了 __xor__() 或 __rxor__() 特殊方法的自定义对象;
  • | 运算符会对其参数执行按位 (合并) OR,参数必须都为整数或者其中之一必须为重载了 __or__() 或 __ror__() 特殊方法的自定义对象。

十、比较运算

参见《Python比较运算》。

十一、布尔运算

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, None, 所有类型的数字零,以及空字符串和空容器(包括字符串、元组、列表、字典、集合与冻结集合)。 所有其他值都会被解读为真值。 用户自定义对象可通过提供 __bool__() 方法来定制其逻辑值。

运算符 not 将在其参数为假值时产生 True,否则产生 False。

  • 表达式 x and y 首先对 x 求值;如果 x 为假则返回该值;否则对 y 求值并返回其结果值;
  • 表达式 x or y 首先对 x 求值;如果 x 为真则返回该值;否则对 y 求值并返回其结果值。

请注意 and 和 or 都不限制其返回的值和类型必须为 False 和 True,而是返回最后被求值的操作数。 此行为是有必要的,例如假设 s 为一个当其为空时应被替换为某个默认值的字符串,表达式 s or 'foo' 将产生希望的值。 由于 not 必须创建一个新值,不论其参数为何种类型它都会返回一个布尔值(例如,not 'foo' 结果为 False 而非 ''。)

十二、 赋值表达式

assignment_expression ::= [identifier ":="] expression

赋值表达式(有时又被称为“命名表达式”或“海象表达式”)将一个 expression 赋值给一个 identifier,同时还会返回 expression 的值。

一个常见用例是在处理匹配的正则表达式的时候:

if matching := pattern.search(data):
do_something(matching)

或者是在处理分块的文件流的时候:

while chunk := file.read(9000):
process(chunk)

赋值表达式在被用作表达式语句及在被用作切片、条件表达式、lambda 表达式、关键字参数和推导式中的 if 表达式以及在 assert, with 和 assignment 语句中的子表达式时必须用圆括号括起来。 在其可使用的其他场合,圆括号则不是必须的,包括在 if 和 while 语句中。

十三、条件表达式

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

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

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

十四、 lambda表达式

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

lambda 表达式(有时称为 lambda 构型)被用于创建匿名函数。 表达式 lambda parameters: expression 会产生一个函数对象 。 该未命名对象的行为类似于用以下方式定义的函数:

def <lambda>(parameters):
return expression

十五、表达式列表

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

除了作为列表或集合显示的一部分,包含至少一个逗号的表达式列表将生成一个元组。 元组的长度就是列表中表达式的数量。 表达式将从左至右被求值。

一个星号 * 表示 可迭代拆包。 其操作数必须为一个 iterable。 该可迭代对象将被拆解为迭代项的序列,并被包含于在拆包位置上新建的元组、列表或集合之中。

末尾的逗号仅在创建单独元组 (或称 单例) 时需要;在所有其他情况下都是可选项。 没有末尾逗号的单独表达式不会创建一个元组,而是产生该表达式的值。 (要创建一个空元组,应使用一对内容为空的圆括号: ()。)

十六、求值顺序

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

十七、运算符优先级

参见《Python运算符优先级》。

广告合作
QQ群号:707632017

温馨提示:

1、本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。邮箱:2942802716#qq.com。(#改为@)

2、本站原创内容未经允许不得转裁,转载请注明出处“站长百科”和原文地址。

目录