zoukankan      html  css  js  c++  java
  • RealPython 基础教程:Python 运算符和表达式

    在了解了不同类型变量之后,我们现在该用这些变量做点什么了。

    今天,我们将了解如何在变量上执行计算。你最终将会掌握如何使用变量和操作符来创建复杂的表达式。

    realpython.cn 正在翻译《RealPython 基础教程》,敬请关注!】

    Python 中,运算符(operators)是一些特殊的符号,用来指明可以执行某种计算。

    那些被运算符操作的值叫做操作数(operands)。

    >>> a = 10
    >>> b = 20
    >>> a + b
    30

    这个简单的例子中,运算符 + 将 a 和 b 两个操作数相加。

    操作数既可以是字面常量,也可以是指向对象的变量。

    >>> a + b -5
    25

    像 a + b - 5 这样由运算符和操作数组成的序列称为表达式。

    Python 提供了众多的运算符来将各种对象组成表达式。

    我们按照运算类型分别介绍一下这些运算符。


    【算术运算符】

    顾名思义,算术运算符是用来做算术运算的。

    下表列举了 Python 支持的算术运算符。

    运算符例子用途运算结果
    +(一元) +a 对操作数取正 a,无实际意义
    +(二元) a + b 操作数相加 a 和 b 之和
    -(一元) -a 对操作数取负 a的负数
    -(二元) a - b 操作数相减 a 和 b 之差
    * a * b 操作数相乘 a 和 b 之积
    / a / b 操作数相除 a 除以 b 的商,结果为 float 类型
    % a % b 求模 a 除以 b 的余数
    // a // b 地板除(floor division):
    两数相除,结果向下取整
    a 除以 b 的商,并取小于等于且最接近此商值的整数
    ** a ** b 幂运算 a 的 b 次幂

    看一些例子:

    >>> a = 4
    >>> b = 3
    >>> +a
    4
    >>> -b
    -3
    >>> a+b
    7
    >>> a-b
    1
    >>> a*b
    12
    >>> a/b
    1.3333333333333333
    >>> a%b
    1
    >>> a ** b
    64
    >>> a // b
    1

    除法(/)运算的结果始终为 float 类型,即使可以整除。

    >>> 10 /5
    2.0
    >>> type(10 / 5)
    <class 'float'>

    对于地板除(floor division),若结果为正,小数部分被舍弃;若结果为负,结果被约等为和其值最接近的不大于该值的整数。你可以这样统一理解,地板除的结果就是取数轴上结果点左侧最靠近它的那个整数。

    >>> 10 / 4
    2.5
    >>> 10 // 4
    2
    >>>
    >>> 10 / -4
    -2.5
    >>> 10 // -4
    -3
    >>>
    >>> -10 / -4
    2.5
    >>> -10 // -4
    2

    【比较运算符】

    比较运算符用于比较两个对象的“大小”。不同对象有其自定义的“大小”语义。

    下表列举了 Python 支持的比较运算符。

    运算符例子用途运算结果
    == a == b 比较操作数是否相等 True,若 a 等于 b;False,若不相等。
    != a != b 比较操作数是否不等 True,若 a 不等于 b;False,若相等
    < a < b 小于比较 True,若 a 小于 b;False,若不小于
    <= a <= b 小于或等于比较 True,若 a 小于或等于 b;False,若大于
    > a > b 大于比较 True,若 a 大于 b;False,若不大于
    >= a >= b 大于或等于比较 True,若 a 大于或等于 b;False,若小于

    看一些例子:

    >>> a = 10
    >>> b = 20
    >>> a == b
    False
    >>> a != b
    True
    >>> a <= b
    True
    >>> a >= b
    False
    >>>
    >>> b = 20
    >>> a == b
    False

    比较运算符通常用于 Boolean 上下文中,比如条件和循环语句,以改变程序的控制流程。

    这里需要注意一下浮点数的等值比较。

    我们在 Python 变量中介绍过,存储在 float 对象中的数值可能并非你所想的那么精确。因此,直接比较两个浮点数是否相等,通常是不可取的操作。

    >>> x = 1.1 + 2.2
    >>> x == 3.3
    False
    >>> x
    3.3000000000000003

    正确的做法是:比较两个浮点数是否足够接近彼此,它们的“距离”在可接受的误差范围内即认为两者相等。

    >>> distance = 0.00001
    >>> x = 1.1 + 2.2
    >>> abs(x - 3.3) < distance
    True

    【逻辑运算符】

    逻辑运算符包括:not、or 和 and。这三者可连接和修改 Boolean 上下文中的表达式,从而表达更复杂的条件语义。

    1,包含 Boolean 类型操作数的逻辑表达式

    我们知道,Python 中有些对象和表达式的值可以是 True 或 False,这时候,这些对象和表达式实际上就是 Boolean 类型。

    >>> x = 5
    >>> x < 10
    True
    >>> type(x < 10)
    <class 'bool'>
    >>>
    >>> t = x > 10
    >>> t
    False
    >>> type(t)
    <class 'bool'>
    >>>
    >>> callable(x)
    False
    >>> type(callable(x))
    <class 'bool'>
    >>>
    >>> t = callable(len)
    >>> t
    True
    >>> type(t)
    <class 'bool'>

    在上边这些例子中,x<10、callable(x)、t 都是 Boolean 类型的对象或表达式。

    当表达式中含有这些 Boolean 类型的操作数时,计算表达式的值很简单。

    可根据下表来计算:

    运算符例子含义
    not not x True,若 x 是False;False,若 x 是 True
    or x or y True,若 x 或 y 是 True;否则,False
    and x and y True,若 x 和 y 均为 True;否则,False

    看一些例子:

    >>> x = 5
    >>> x < 10
    True
    >>> not x < 10
    False
    >>> callable(x)
    False
    >>> not callable(x)
    True
    >>>
    >>> x < 10 or callable(x)
    True
    >>> x < 0 or callable(x)
    False
    >>>
    >>> x < 10 and callable(x)
    False
    >>> x < 10 and callable(len)
    True

    2,非 Boolean 类型的值在 Boolean 上下文中的求值

    Python 中还有很多对象和表达式的值并不等于 True 或 False,即它们非 Boolean 类型。

    尽管如此,在需要进行 Boolean 计算的环境中,这些对象或表达式也可以被适当处理,从而被视为“真值(truthy)”或“假值(falsy)”。

    那么,到底何为真?何为假?嗯,这可以上升为一个较难回答的哲学问题。

    但在 Python 中,真与假却是良好定义的。

    在 Boolean 上下文中,以下这些情况均视作假:

    • Boolean 类型值:False

    • 任何在数字上等于0的值:0、0.0、0.0+0.0j

    • 空字符串:''

    • 任何空的内置组合数据类型

    • 关键字 None 表示的值

    其他 Python 内置的对象可判为真。

    我们可以使用 bool() 函数来判断一个对象或表达式是否为真。若参数为真值,bool() 返回 True,否则返回 False。

    数字数值的 Boolean 判定方法:

    值为 0 的数字为 False,非 0 值为 True。

    >>> print(bool(0), bool(0.0), bool(0.0+0.0j))
    False False False
    >>> print(bool(-3), bool(3.14159), bool(1.0+1j))
    True True True

    字符串的 Boolean 判定方法:

    空字符串为 False,非空字符串为 True。

    >>> print(bool(''), bool(""), bool(""""""))
    False False False
    >>> print(bool('foo'), bool(" "), bool(''' '''))
    True True True

    内置组合类型对象的 Boolean 判定方法:

    Python 内置的组合数据类型包括:list、tuple、dict 和 set。它们是可以包含其他对象的“容器”。

    当这些容器不含任何其他对象时,这些容器就是空的。若容器为空,容器对象就视作假;容器非空,容器对象就视作真。

    >>> type([])
    <class 'list'>
    >>> bool([])
    False
    >>> type([1, 2, 3])
    <class 'list'>
    >>> bool([1, 2, 3])
    True

    关键字 None 永远为假。

    >>> bool(None)
    False

    3,包含非 Boolean 类型操作数的逻辑表达式

    非 Boolean 类型的值也可用在逻辑表达式中,通过 not、or 和 and 来修改或组合。表达式的计算结果依赖于这些非 Boolean 操作数的真假。

    注意:这里,表达式的结果不一定是 Boolean 值!

    not 作用于非 Boolean 操作数:

    当 x 为: not x 为:
    真值 False
    假值 True

    例如:

    >>> x = 3
    >>> bool(x)
    True
    >>> not x
    False
    >>>
    >>> x = 0.0
    >>> bool(x)
    False
    >>> not x
    True

    or 作用于非 Boolean 操作数:

    当 x 为: x or y 为:
    真值 x
    假值 y

    例如:

    >>> x = 3
    >>> y = 4
    >>> x or y
    3
    >>> x = 0.0
    >>> y = 4.4
    >>> x or y
    4.4

    and 作用于非 Boolean操作数:

    当 x 为: x and y 为:
    真值 y
    假值 x

    例如:

    >>> x = 3
    >>> y = 4
    >>> x and y
    4
    >>> x = 0.0
    >>> y = 4.4
    >>> x and y
    0.0

    4,复合表达式与短路求值

    我们在上文列举的例子都是使用了一个运算符和至多两个操作数:

    x or y
    x and y

    实际上,多个运算符和操作数也可以连在一起使用,形成复合逻辑表达式。

    复合 or 表达式形式如下:

    x1 or x2 or x3 or ... xn

    当 xi 中任一操作数为True 时,表达式为 True。

    在处理这类包含多个逻辑运算符的表达式时,Python 采用“短路求值”法来计算表达式的值。解释器会从左向右逐一计算每个操作数 xi 的值。一旦遇到一个 xi 的值为 True,整个表达式就被认为是 True,此时,解释器不再继续向右计算,表达式的值就是最后那个已计算的 xi 操作数的值

    请注意体会“表达式的真假值”和“表达式的值”的区别,我们有时候会混用这两个概念。

    为便于理解“短路求值”,我们可以设计一个简单的函数 f(),该函数的功能为:

    • f() 接受一个单一的值作为参数

    • f() 将参数输出到控制台

    • f() 将参数作为返回值返回

    这是几个调用 f() 的例子:

    >>> f(0)
    -> f(0) = 0
    0
    >>>
    >>> f(False)
    -> f(False) = False
    False
    >>>
    >>> f(1.5)
    -> f(1.5) = 1.5
    1.5

    我们可以向 f() 传递具有真值或假值的参数,以使得 f(arg) 的值也为真或假。并且,通过控制台的输出,我们能看到复合逻辑表达式中某一部分是否被调用了。

    来看下边这个复合逻辑表达式:

    >>> f(0) or f(False) or f(1) or f(2) or f(3)
    -> f(0) = 0
    -> f(False) = False
    -> f(1) = 1
    1

    按照上边的介绍,f(0)、f(False) 依次被调用,直到 f(1) 为 True 时,表达式已能被判定为 True,计算到此结束,表达式的值就是 f(1) 的值。f(2) 和 f(3) 不会被执行到。

    复合 and 表达式形式如下:

    x1 and x2 and x3 and ... xn

    所有 xi 均为 True,表达式才为 True。

    短路求值对复合 and 表达式的处理逻辑为:从左到右依次计算每个操作数的真假值,一旦遇到一个 xi 的值为 False,整个表达式就被判定为 False,计算结束,表达式的值就是最后那个已计算的 xi 操作数的值。

    仍使用 f() 函数来看两个例子:

    >>> f(1) and f(False) and f(2) and f(3)
    -> f(1) = 1
    -> f(False) = False
    False
    >>>
    >>> f(1) and f(0.0) and f(2) and f(3)
    -> f(1) = 1
    -> f(0.0) = 0.0
    0.0

    这两个表达式的计算过程都停止在第一个为假值的操作数上:f(False)、f(0.0),表达式的值分别为 False 和 0.0。后边的 f(2) 和 f(3) 没有被调用。

    如果所有的操作数都是真值,那么它们都会被计算,最后一个操作数的值就是表达式的值。

    >>> f(1) and f(2.2) and f('bar')
    -> f(1) = 1
    -> f(2.2) = 2.2
    -> f(bar) = bar
    'bar'


    短路求值在实际应用中有一些惯用场景:

    a, 避免出现异常

    假设有两个变量:a 和 b。我们想要判断 (b / a) 是否大于 0.

    >>> a = 3
    >>> b = 1
    >>> (b / a) > 0
    True

    这里,需要注意 a 的值不能为 0,否则会导致异常:

    >>> a = 0
    >>> b = 1
    >>> (b / a) > 0
    Traceback (most recent call last):
    File "<stdin>", line 1,
    in <module>
    ZeroDivisionError: division by zero

    我们可借助短路求值避免这种异常:

    >>> a = 0
    >>> b = 1
    >>> a != 0 and (b / a) > 0
    False

    a 为 0 时,a != 0 为假值,and 表达式求值结束,右边的除法运算不会执行到。

    对于这个问题,我们还可以写出更简单的表达式:

    >>> a = 0
    >>> b = 1
    >>> a and (b / a) > 0
    0

    作为数字,a 为 0 时,其就是一个假值,and 表达式也会结束求值过程。

    b, 选择默认值

    为变量赋值时,若遇到 0 或 空值,可借助短路求值为变量赋一个默认值。

    比如,我们想使用字符串 s2 为字符串 s1 赋值,如果 s2 为空字符串,我们可以为 s1 指定一个默认值。

    >>> s2 = "World"
    >>> s1 = s2 or 'Hello'
    >>> s1
    'World'
    >>>
    >>> s2 = ''
    >>> s1 = s2 or 'Hello'
    >>> s1
    'Hello'

    5,链式比较

    在 Python 中,多个比较运算符可以串联起来使用。

    比如,下边这两个表达式基本相同:

    >>> x < y <= z
    >>> x < y and y <= z

    它们有一点区别:y 的计算次数不同。x < y <= z 中,y 只计算一次;x < y and y <= z 中,y 会被计算两次。

    如果 y 只是一个静态值,比如 1,这种差别微乎其微。但假如 y 是一个复杂的表达式,少一次计算可能会带来可观的效率上的提升。例如:

    x < f() <= z
    x < f() and f() <= z

    更一般的情况,如果 op1、op2、op...、opn 是比较运算符,那么下边的表达式具有相同的 Boolean 值:

    x1 op1 x2 op2 x3 ... opn xn
    x1 op1 x2 and x2 op2 x3 and x3 ... opn xn

    同样,前者中的 xi 只计算一次,而后者中的非首尾的 xi 会计算两次,除非计算提前结束。


    【位操作运算符】

    位操作运算符将操作数视为二进制序列,对操作数进行逐位运算。

    下表列举了 Python 支持的位操作运算符。

    运算符例子含义结果
    & a & b 按位与 两个操作数对应位相与(全1则1,否则为0)
    | a | b 按位或 两个操作数对应位相或(有1则1,全0为0)
    ~ ~a 取反 对操作数的每一位取反(0则1,1则0)
    ^ a ^ b 异或 两个操作数对应位异或(异则1,同则0)
    >> a >> n 右移 将操作数右移n位
    << a << n 左移 将操作数左移n位

    看一些例子:

    >>> '0b{:04b}'.format(0b1100 & 0b1010)
    '0b1000'
    >>> '0b{:04b}'.format(0b1100 | 0b1010)
    '0b1110'
    >>> '0b{:04b}'.format(0b1100 ^ 0b1010)
    '0b0110'
    >>> '0b{:04b}'.format(0b1100 >> 2)
    '0b0011'
    >>> '0b{:04b}'.format(0b0011 << 2)
    '0b1100'

    这里,以二进制的形式来表示操作数和运算结果,可以清晰地看出位运算的执行逻辑。


    【ID 运算符】

    id 运算符用于判断两个操作数是否拥有相同 id,也即是否指向同一对象。

    这和“相等”不是同一个概念,相等表示两个操作数的值相等,而它们不一定指向同一个对象。

    Python 提供 is 和 is not 两个 id 运算符。

    看一些例子:

    >>> a = 798
    >>> b = 798
    >>> a == b #相等
    True
    >>> a is b #id 不同
    False
    >>>
    >>> a = 798
    >>> b = a
    >>> a is b  #a、b 指向同一对象,id 相同
    True

    可结合 《一文理解 Python 中的变量》来理解。


    【运算符的优先级】

    我们都知道算术中的混合运算可以包含多种运算符,这些运算符可改变运算顺序。

    >>> 20 + 4 * 10
    60

    在这个例子中,同时存在 + 和 * 两种运算符,按照算术规则,先算乘法后算加法,乘法优先级高于加法。

    Python 中的每个运算符也都有一定的优先级。优先级高的运算符先被执行,优先级相同的运算符按照从左向右的顺序执行。

    我们目前已使用了多种运算符,按优先级从低到高列表如下:

     运算符描述
    最低优先级 or Boolean 或
      and Boolean 且
      not Boolean 非
      ==、!=、<、<=、>、>=、is、is not 比较运算、id运算
      | 按位或
      ^ 异或
      & 按位与
      <<、>> 移位操作
      +、- 加减
      *、/、//、% 乘除、地板除、取模
      +x、-x、~x 一元正负、按位取反
    最高优先级 ** 幂运算

    看一些例子:

    >>> 2 * 3 ** 4 * 5
    810

    括号可以改变运算符的优先级,并且有助于理解运算的先后顺序。

    >>> 20 + 4 * 10
    60
    >>> (20 + 4) * 10
    240
    >>> 2 * 3 ** 4 * 5
    810
    >>> 2 * 3 ** (4 * 5)
    6973568802

    【扩展的赋值运算符】

    赋值(=)运算符用于为变量赋值。既可以为变量赋静态值,也可以为其赋予一个包含其他变量的表达式,并且表达式中还可以包含变量自身。

    >>> a = 10
    >>> b = 20
    >>> c = a * 5 + b
    >>> c
    70
    >>> a = a + 5
    >>> a
    15
    >>> b = b * 3
    >>> b
    60

    对于 a=a+5、b=b*3 这种赋值形式,其含义是在变量自身基础上再进行赋值操作。其前提是,变量必须已经被赋予了初值,否则导致错误。

    >>> i = i / 12
    Traceback (most recent call last):
    File "<stdin>", line 1,
    in <module>
    NameError: name 'i' is not defined

    Python 为上边这种赋值方式提供了一个简写形式:

    x <op>= y

    这种简写等同于:

    x = x <op> y

    支持这种扩展赋值方式的运算符包括:

    +、=、*、/、%、//、**、&、|、^、>>、<<

    看一些例子:

    >>> a = 5
    >>> a += 2
    >>> a
    7
    >>> b = 16
    >>> b /= 4
    >>> b
    4.0

    【结语】

    本文详细介绍了 Python 提供的各种运算符,以及如何这些运算符来生成表达式。

    特别指出了浮点比较运算、短路求值等细节性问题,相信会对你理解和使用运算符和表达式提供帮助。


    我们接下来会学一个非常重要的数据类型:字符串。

    realpython.cn 正在翻译《RealPython 基础教程》,敬请关注!】

  • 相关阅读:
    【loj6179】Pyh的求和
    【bzoj4036】按位或
    【CF472G】Design Tutorial: Increase the Constraints
    【bzoj4811】由乃的OJ
    双马尾机器人(???)
    【codechef】Children Trips
    【bzoj3796】Mushroom追妹纸
    【bzoj4571】美味
    前夕
    【bzoj3589】动态树
  • 原文地址:https://www.cnblogs.com/rd-log/p/14363268.html
Copyright © 2011-2022 走看看