五、Python数据及运算符

所有的编程语言都支持变量,Python 也不例外。变量是编程的起点,程序需要将数据存储到变量中。

变量在 Python 内部是有类型的,比如 int、float 等,但是我们在编程时无需关注变量类型,所有的变量都无需提前声明,赋值后就能使用。另外,可以将不同类型的数据赋值给同一个变量,所以变量的类型是可以改变的。

本章的另一个重点内容是运算符,运算符将各种类型的数据连接在一起形成表达式。Python 的运算符丰富但不混乱,比如 Python 支持自增和自减运算符,但是它只支持一种形式,就是前自增和前自减,而取消了后自增和后自减,避免了给程序员造成混乱。

5.1 变量定义

任何编程语言都需要处理数据,比如数字、字符串、字符等,我们可以直接使用数据,也可以将数据保存到变量中,方便以后使用。

变量(Variable)可以看成一个小箱子,专门用来“盛装”程序中的数据。每个变量都拥有独一无二的名字,通过变量的名字就能找到变量中的数据。

从底层看,程序中的数据最终都要放到内存(内存条)中,变量其实就是这块内存的名字。

和变量相对应的是常量(Constant),它们都是用来“盛装”数据的小箱子,不同的是:变量保存的数据可以被多次修改,而常量一旦保存某个数据之后就不能修改了。
Python 变量的赋值
在编程语言中,将数据放入变量的过程叫做赋值(Assignment)。Python 使用等号=作为赋值运算符,具体格式为:

name = value
name 表示变量名;value 表示值,也就是要存储的数据。

注意,变量是标识符的一种,它的名字不能随便起,要遵守 Python 标识符命名规范,还要避免和 Python 内置函数以及 Python 保留字重名。

例如,下面的语句将整数 10 赋值给变量 n:

n = 10

从此以后,n 就代表整数 10,使用 n 也就是使用 10。
更多赋值的例子:

pi = 3.1415926  #将圆周率赋值给变量 pi
url = ""  #将 Python 教程的地址赋值给变量 str
real = True  #将布尔值赋值给变量 real

变量的值不是一成不变的,它可以随时被修改,只要重新赋值即可;另外你也不用关心数据的类型,可以将不同类型的数据赋值给同一个变量。请看下面的演示:

n = 10  #将10赋值给变量n
n = 95  #将95赋值给变量n
n = 200  #将200赋值给变量n
abc = 12.5  #将小数赋值给变量abc
abc = 85  #将整数赋值给变量abc
abc = ""  #将字符串赋值给变量abc

注意,变量的值一旦被修改,之前的值就被覆盖了,不复存在了,再也找不回了。换句话说,变量只能容纳一个值。

除了赋值单个数据,你也可以将表达式的运行结果赋值给变量,例如:

sum = 100 + 20  #将加法的结果赋值给变量
rem = 25 * 30 % 7  #将余数赋值给变量
str = "Python" + ""  #将字符串拼接的结果赋值给变量

Python 变量的使用
使用 Python 变量时,只要知道变量的名字即可。
几乎在 Python 代码的任何地方都能使用变量,请看下面的演示:

>>> n = 10
>>> print(n)  #将变量传递给函数
10
>>> m = n * 10 + 5  #将变量作为四则运算的一部分
>>> print(m)
105
>>> print(m-30)  #将由变量构成的表达式作为参数传递给函数
75
>>> m = m * 2  #将变量本身的值翻倍
>>> print(m)
210
>>> url = ""
>>> str = "Python教程:" + url  #字符串拼接
>>> print(str)
Python教程:

Python 是弱类型的语言
在强类型的编程语言中,定义变量时要指明变量的类型,而且赋值的数据也必须是相同类型的,C语言、C++、Java 是强类型语言的代表。

下面我们以 C++ 为例来演示强类型语言中变量的使用:

int n = 10;  //int表示整数类型
n = 100;
n = "";  //错误:不能将字符串赋值给整数类型
url = "";  //错误:没有指明类型的变量是没有定义的,不能使用。

和强类型语言相对应的是弱类型语言,Python、JavaScript、PHP 等脚本语言一般都是弱类型的。

弱类型语言有两个特点:
变量无须声明就可以直接赋值,对一个不存在的变量赋值就相当于定义了一个新变量。
变量的数据类型可以随时改变,比如,同一个变量可以一会儿被赋值为整数,一会儿被赋值为字符串。

注意,弱类型并不等于没有类型!弱类型是说在书写代码时不用刻意关注类型,但是在编程语言的内部仍然是有类型的。我们可以使用 type() 内置函数类检测某个变量或者表达式的类型,例如:

>>> num = 10
>>> type(num)
<class 'int'>
>>> num = 15.8
>>> type(num)
<class 'float'>
>>> num = 20 + 15j
>>> type(num)
<class 'complex'>
>>> type(3*15.6)
<class 'float'>

5.2 数据类型

5.2.1 整数类型(int)

整数就是没有小数部分的数字,Python 中的整数包括正整数、0 和负整数。

有些强类型的编程语言会提供多种整数类型,每种类型的长度都不同,能容纳的整数的大小也不同,开发者要根据实际数字的大小选用不同的类型。例如C语言提供了 short、int、long、long long 四种类型的整数,它们的长度依次递增,初学者在选择整数类型时往往比较迷惑,有时候还会导致数值溢出。

而 Python 则不同,它的整数不分类型,或者说它只有一种类型的整数。Python 整数的取值范围是无限的,不管多大或者多小的数字,Python 都能轻松处理。
当所用数值超过计算机自身的计算能力时,Python 会自动转用高精度计算(大数计算)。

请看下面的代码:

#将 78 赋值给变量 n
n = 78
print(n)
print( type(n) )
#给x赋值一个很大的整数
x = 8888888888888888888888
print(x)
print( type(x) )
#给y赋值一个很小的整数
y = -7777777777777777777777
print(y)
print( type(y) )
运行结果:
78
<class 'int'>
8888888888888888888888
<class 'int'>
-7777777777777777777777
<class 'int'>

x 是一个极大的数字,y 是一个很小的数字,Python 都能正确输出,不会发生溢出,这说明 Python 对整数的处理能力非常强大。

不管对于多大或者多小的整数,Python 只用一种类型存储,就是 int。
关于 Python 2.x
Python 3.x 只用 int 一种类型存储整数,但是 Python 2.x 会使用 long 类型来存储较大的整数。以上代码在 Python 2.x 下的运行结果为:

78
<type 'int'>
8888888888888888888888
<type 'long'>
-7777777777777777777777
<type 'long'>

但是不管哪个版本的 Python,都能轻松处理极大和极小的数字,而且程序员也不用操心底层到底使用了 int 还是 long 类型。

5.2.1.1 整数的不同进制

在 Python 中,可以使用多种进制来表示整数:

  1. 十进制形式
    我们平时常见的整数就是十进制形式,它由 0~9 共十个数字排列组合而成。
    注意,使用十进制形式的整数不能以 0 作为开头,除非这个数值本身就是 0。
  2. 二进制形式
    由 0 和 1 两个数字组成,书写时以0b或0B开头。例如,101 对应十进制数是 5。
  3. 八进制形式
    八进制整数由 0~7 共八个数字组成,以0o或0O开头。注意,第一个符号是数字 0,第二个符号是大写或小写的字母 O。
    在 Python 2.x 中,八进制数字还可以直接以0(数字零)开头。
  4. 十六进制形式
    由 0~9 十个数字以及 A~F(或 a~f)六个字母组成,书写时以0x或0X开头,

进制的转换,可以自行查资料学习。
【实例】不同进制整数在 Python 中的使用:

#十六进制
hex1 = 0x45
hex2 = 0x4Af
print("hex1Value: ", hex1)
print("hex2Value: ", hex2)
#二进制
bin1 = 0b101
print('bin1Value: ', bin1)
bin2 = 0B110
print('bin2Value: ', bin2)
#八进制
oct1 = 0o26
print('oct1Value: ', oct1)
oct2 = 0O41
print('oct2Value: ', oct2)
运行结果:
hex1Value:  69
hex2Value:  1199
bin1Value:  5
bin2Value:  6
oct1Value:  22
oct2Value:  33

本例的输出结果都是十进制整数。

5.2.1.2 数字分隔符

为了提高数字的的可读性,Python 3.x 允许使用下划线_作为数字(包括整数和小数)的分隔符。通常每隔三个数字添加一个下划线,类似于英文数字中的逗号。下划线不会影响数字本身的值。

【实例】使用下划线书写数字:

click = 1_301_547
distance = 384_000_000
print("Python教程阅读量:", click)
print("地球和月球的距离:", distance)
运行结果:
Python教程阅读量:1301547
地球和月球的距离:384000000

5.2.2 浮点数(float)

在编程语言中,小数通常以浮点数的形式存储。浮点数和定点数是相对的:小数在存储过程中如果小数点发生移动,就称为浮点数;如果小数点不动,就称为定点数。
Python 中的小数有两种书写形式:

  1. 十进制形式
    这种就是我们平时看到的小数形式,例如 34.6、346.0、0.346。
    书写小数时必须包含一个小数点,否则会被 Python 当作整数处理。
  2. 指数形式,就是我们小学学的科学计数法。
    Python 小数的指数形式的写法为:
aEn 或 aen
a 为尾数部分,是一个十进制数;n 为指数部分,是一个十进制整数;E或e是固定的字符,用于分割尾数部分和指数部分。整个表达式等价于 a×10n。

指数形式的小数举例:
2.1E5 = 2.1×105,其中 2.1 是尾数,5 是指数。
3.7E-2 = 3.7×10-2,其中 3.7 是尾数,-2 是指数。
0.5E7 = 0.5×107,其中 0.5 是尾数,7 是指数。

注意,只要写成指数形式就是小数,即使它的最终值看起来像一个整数。例如 14E3 等价于 14000,但 14E3 是一个小数。

Python 只有一种小数类型,就是 float。C语言有两种小数类型,分别是 float 和 double:float 能容纳的小数范围比较小,double 能容纳的小数范围比较大。

【实例】小数在 Python 中的使用:

f1 = 12.5
print("f1Value: ", f1)
print("f1Type: ", type(f1))
f2 = 0.34557808421257003
print("f2Value: ", f2)
print("f2Type: ", type(f2))
f3 = 0.0000000000000000000000000847
print("f3Value: ", f3)
print("f3Type: ", type(f3))
f4 = 345679745132456787324523453.45006
print("f4Value: ", f4)
print("f4Type: ", type(f4))
f5 = 12e4
print("f5Value: ", f5)
print("f5Type: ", type(f5))
f6 = 12.3 * 0.1
print("f6Value: ", f6)
print("f6Type: ", type(f6))
运行结果:
f1Value:  12.5
f1Type:  <class 'float'>
f2Value:  0.34557808421257
f2Type:  <class 'float'>
f3Value:  8.47e-26
f3Type:  <class 'float'>
f4Value:  3.456797451324568e+26
f4Type:  <class 'float'>
f5Value:  120000.0
f5Type:  <class 'float'>
f6Value:  1.2300000000000002
f6Type:  <class 'float'>

从运行结果可以看出,Python 能容纳极小和极大的浮点数。print 在输出浮点数时,会根据浮点数的长度和大小适当的舍去一部分数字,或者采用科学计数法。
f5 的值是 120000,但是它依然是小数类型,而不是整数类型。

让人奇怪的是 f6,12.3*0.1的计算结果很明显是 1.23,但是 print 的输出却不精确。这是因为小数在内存中是以二进制形式存储的,小数点后面的部分在转换成二进制时很有可能是一串无限循环的数字,无论如何都不能精确表示,所以小数的计算结果一般都是不精确的。
关于浮点数类型在计算机中的存储,感兴趣的可以自己查资料补全知识点。

5.2.3 复数(complex)

复数(Complex)是 Python 的内置类型,直接书写即可。换句话说,Python 语言本身就支持复数,而不依赖于标准库或者第三方库。

复数由实部(real)和虚部(imag)构成,在 Python 中,复数的虚部以j或者J作为后缀,具体格式为:

a + bj

a 表示实部,b 表示虚部。

【实例】Python 复数的使用:

c1 = 12 + 0.2j
print("c1Value: ", c1)
print("c1Type", type(c1))
c2 = 6 - 1.2j
print("c2Value: ", c2)
#对复数进行简单计算
print("c1+c2: ", c1+c2)
print("c1*c2: ", c1*c2)
运行结果:
c1Value:  (12+0.2j)
c1Type <class 'complex'>
c2Value:  (6-1.2j)
c1+c2:  (18-1j)
c1*c2:  (72.24-13.2j)

可以发现,复数在 Python 内部的类型是 complex,Python 默认支持对复数的简单计算。

5.2.4 字符串(String)

5.2.4.1 普通字符串

若干个字符的集合就是一个字符串(String)。Python 中的字符串必须由双引号" "或者单引号’ '包围,具体格式为:
“字符串内容”
‘字符串内容’
字符串的内容可以包含字母、标点、特殊符号、中文、日文等全世界的所有文字。
下面都是合法的字符串:
“123789”
“123abc”
“”
“Python学习”
Python 字符串中的双引号和单引号没有任何区别。而有些编程语言的双引号字符串可以解析变量,单引号字符串一律原样输出,例如 PHP 和 JavaScript。

  1. 处理字符串中的引号的
    当字符串内容中出现引号时,我们需要进行特殊处理,否则 Python 会解析出错,例如:
'I'm a great coder!'

由于上面字符串中包含了单引号,此时 Python 会将字符串中的单引号与第一个单引号配对,这样就会把’I’当成字符串,而后面的m a great coder!'就变成了多余的内容,从而导致语法错误。
对于这种情况,我们有两种处理方案:

  1. 对引号进行转义
    在引号前面添加反斜杠\就可以对引号进行转义,让 Python 把它作为普通文本对待,例如:
str1 = 'I\'m a great coder!'
str2 = "引文双引号是\",中文双引号是“"
print(str1)
print(str2)
运行结果:
I'm a great coder!
引文双引号是",中文双引号是“
  1. 使用不同的引号包围字符串
    如果字符串内容中出现了单引号,那么我们可以使用双引号包围字符串,反之亦然。例如:
str1 = "I'm a great coder!"  #使用双引号包围含有单引号的字符串
str2 = '引文双引号是",中文双引号是“'  #使用单引号包围含有双引号的字符串
print(str1)
print(str2)

运行结果和上面相同。

  1. 字符串的换行
    Python 不是格式自由的语言,它对程序的换行、缩进都有严格的语法要求。要想换行书写一个比较长的字符串,必须在行尾添加反斜杠\,请看下面的例子:
s2 = 'It took me six months to write this Python tutorial. \
    Please give me more support. \
    I will keep it updated.'
    ```
上面 s2 字符串的比较长,所以使用了转义字符\对字符串内容进行了换行,这样就可以把一个长字符串写成多行。

另外,Python 也支持表达式的换行,例如:
```markdown
num = 20 + 3 / 4 + \
    2 * 3
print(num)
  1. Python长字符串
    在《Python注释》一节中我们提到,使用三个单引号或者双引号可以对多行内容进行注释,这其实是 Python 长字符串的写法。所谓长字符串,就是可以直接换行(不用加反斜杠\)书写的字符串。

Python 长字符串由三个双引号"""或者三个单引号’''包围,语法格式如下:

"""长字符串内容"""
'''长字符串内容'''

在长字符串中放置单引号或者双引号不会导致解析错误。

如果长字符串没有赋值给任何变量,那么这个长字符串就不会起到任何作用,和一段普通的文本无异,相当于被注释掉了。
注意,此时 Python 解释器并不会忽略长字符串,也会按照语法解析,只是长字符串起不到实际作用而已。

当程序中有大段文本内容需要定义成字符串时,优先推荐使用长字符串形式,因为这种形式非常强大,可以在字符串中放置任何内容,包括单引号和双引号。

【实例】将长字符串赋值给变量:

longstr = '''It took me 6 months to write this Python tutorial.
Please give me a to 'thumb' to keep it updated.
The Python tutorial is available at '''
print(longstr)

长字符串中的换行、空格、缩进等空白符都会原样输出,所以你不能写成下面的样子:

longstr = '''
    It took me 6 months to write this Python tutorial.
    Please give me a to 'thumb' to keep it updated.
    The Python tutorial is available at http://c.biancheng.net/python/.
'''
print(longstr)

虽然这样写格式优美,但是输出结果将变成:

It took me 6 months to write this Python tutorial.
    Please give me a to 'thumb' to keep it updated.
    The Python tutorial is available at http://c.biancheng.net/python/.

字符串内容前后多出了两个空行,并且每一行的前面会多出四个空格。

5.2.4.2 Python原始字符串

Python 字符串中的反斜杠\有着特殊的作用,就是转义字符,例如上面提到的’和",我们将在《Python转义字符》一节中详细讲解,这里大家先简单了解。

转义字符有时候会带来一些麻烦,例如我要表示一个包含 Windows 路径D:\Program Files\Python 3.8\python.exe这样的字符串,在 Python 程序中直接这样写肯定是不行的,不管是普通字符串还是长字符串。因为\的特殊性,我们需要对字符串中的每个\都进行转义,也就是写成D:\Program Files\Python 3.8\python.exe这种形式才行。

这种写法需要特别谨慎,稍有疏忽就会出错。为了解决转义字符的问题,Python 支持原始字符串。在原始字符串中,\不会被当作转义字符,所有的内容都保持“原汁原味”的样子。

在普通字符串或者长字符串的开头加上r前缀,就变成了原始字符串,具体格式为:

str1 = r'原始字符串内容'
str2 = r"""原始字符串内容"""

将上面的 Windows 路径改写成原始字符串的形式:

rstr = r'D:\Program Files\Python 3.8\python.exe'
print(rstr)
  • 原始字符串中的引号
    如果普通格式的原始字符串中出现引号,程序同样需要对引号进行转义,否则 Python 照样无法对字符串的引号精确配对;但是和普通字符串不同的是,此时用于转义的反斜杠会变成字符串内容的一部分。

请看下面的代码:

str1 = r'I\'m a great coder!'
print(str1)
输出结果:
I\'m a great coder!

需要注意的是,Python 原始字符串中的反斜杠仍然会对引号进行转义,因此原始字符串的结尾处不能是反斜杠,否则字符串结尾处的引号会被转义,导致字符串不能正确结束。

在 Python 中有两种方式解决这个问题:一种方式是改用长字符串的写法,不要使用原始字符串;另一种方式是单独书写反斜杠,这是接下来要重点说明的。

例如想表示D:\Program Files\Python 3.8\,可以这样写:

str1 = r'D:\Program Files\Python 3.8' '\\'
print(str1)

我们先写了一个原始字符串r’D:\Program Files\Python 3.8’,紧接着又使用’\'写了一个包含转义字符的普通字符串,Python 会自动将这两个字符串拼接在一起,所以上面代码的输出结果是:
D:\Program Files\Python 3.8
由于这种写法涉及到了字符串拼接的相关知识,这里读者只需要了解即可,字符串还涉及很多方法、函数,下一章将会对字符串做详细介绍。

5.2.5 字节串类型(bytes)

Python bytes 类型用来表示一个字节串。“字节串“不是编程术语,是我自己“捏造”的一个词,用来和字符串相呼应。
bytes 是 Python 3.x 新增的类型,在 Python 2.x 中是不存在的。

字节串(bytes)和字符串(string)的对比:
字符串由若干个字符组成,以字符为单位进行操作;字节串由若干个字节组成,以字节为单位进行操作。
字节串和字符串除了操作的数据单元不同之外,它们支持的所有方法都基本相同。
字节串和字符串都是不可变序列,不能随意增加和删除数据。

bytes 只负责以字节序列的形式(二进制形式)来存储数据,至于这些数据到底表示什么内容(字符串、数字、图片、音频等),完全由程序的解析方式决定。如果采用合适的字符编码方式(字符集),字节串可以恢复成字符串;反之亦然,字符串也可以转换成字节串。

说白了,bytes 只是简单地记录内存中的原始数据,至于如何使用这些数据,bytes 并不在意,你想怎么使用就怎么使用,bytes 并不约束你的行为。

bytes 类型的数据非常适合在互联网上传输,可以用于网络通信编程;bytes 也可以用来存储图片、音频、视频等二进制格式的文件。

字符串和 bytes 存在着千丝万缕的联系,我们可以通过字符串来创建 bytes 对象,或者说将字符串转换成 bytes 对象。有以下三种方法可以达到这个目的:
如果字符串的内容都是 ASCII 字符,那么直接在字符串前面添加b前缀就可以转换成 bytes。
bytes 是一个类,调用它的构造方法,也就是 bytes(),可以将字符串按照指定的字符集转换成 bytes;如果不指定字符集,那么默认采用 UTF-8。
字符串本身有一个 encode() 方法,该方法专门用来将字符串按照指定的字符集转换成对应的字节串;如果不指定字符集,那么默认采用 UTF-8。

【实例】使用不同方式创建 bytes 对象:

#通过构造函数创建空 bytes
b1 = bytes()
#通过空字符串创建空 bytes
b2 = b''
#通过b前缀将字符串转换成 bytes
b3 = b''
print("b3: ", b3)
print(b3[3])
print(b3[7:22])
#为 bytes() 方法指定字符集
b4 = bytes('Python学习', encoding='UTF-8')
print("b4: ", b4)
#通过 encode() 方法将字符串转换成 bytes
b5 = "Python学习".encode('UTF-8')
print("b5: ", b5)

运行结果,感兴趣的可以去尝试一下。

从运行结果可以发现,对于非 ASCII 字符,print 输出的是它的字符编码值(十六进制形式),而不是字符本身。非 ASCII 字符一般占用两个字节以上的内存,而 bytes 是按照单个字节来处理数据的,所以不能一次处理多个字节。

bytes 类也有一个 decode() 方法,通过该方法可以将 bytes 对象转换为字符串。紧接上面的程序,添加以下代码:
#通过 decode() 方法将 bytes 转换成字符串

str1 = b5.decode('UTF-8')
print("str1: ", str1)

5.2.6 布尔型(bool)

Python 提供了 bool 类型来表示真(对)或假(错),比如常见的5 > 3比较算式,这个是正确的,在程序世界里称之为真(对),Python 使用 True 来代表;再比如4 > 20比较算式,这个是错误的,在程序世界里称之为假(错),Python 使用 False 来代表。
True 和 False 是 Python 中的关键字,当作为 Python 代码输入时,一定要注意字母的大小写,否则解释器会报错。

值得一提的是,布尔类型可以当做整数来对待,即 True 相当于整数值 1,False 相当于整数值 0。因此,下边这些运算都是可以的:

>>> False+1
1
>>> True+1
2

注意,这里只是为了说明 True 和 Flase 对应的整型值,在实际应用中是不妥的,不要这么用。
总的来说,bool 类型就是用于代表某个事情的真(对)或假(错),如果这个事情是正确的,用 True(或 1)代表;如果这个事情是错误的,用 False(或 0)代表。

>>> 5>3
True
>>> 4>20
False

在 Python 中,所有的对象都可以进行真假值的测试,包括字符串、元组、列表、字典、对象等,由于目前尚未学习,因此这里不做过多讲述,后续遇到时会做详细的介绍。

5.2.7 None类型

在 Python 中,有一个特殊的常量 None(N 必须大写)。和 False 不同,它不表示 0,也不表示空字符串,而表示没有值,也就是空值。

这里的空值并不代表空对象,即 None 和 []、“” 不同:

>>> None is []
False
>>> None is ""
False

None 有自己的数据类型,我们可以在 IDLE 中使用 type() 函数查看它的类型,执行代码如下:

>>> type(None)
<class 'NoneType'>

可以看到,它属于 NoneType 类型。

需要注意的是,None 是 NoneType 数据类型的唯一值(其他编程语言可能称这个值为 null、nil 或 undefined),也就是说,我们不能再创建其它 NoneType 类型的变量,但是可以将 None 赋值给任何变量。如果希望变量中存储的东西不与任何其它值混淆,就可以使用 None。

除此之外,None 常用于 assert、判断以及函数无返回值的情况。举个例子,在前面章节中我们一直使用 print() 函数输出数据,其实该函数的返回值就是 None。因为它的功能是在屏幕上显示文本,根本不需要返回任何值,所以 print() 就返回 None。

>>> spam = print('Hello!')
Hello!
>>> None == spam
True

另外,对于所有没有 return 语句的函数定义,Python 都会在末尾加上 return None,使用不带值的 return 语句(也就是只有 return 关键字本身),那么就返回 None。

5.2.8 数据类型转换

虽然 Python 是弱类型编程语言,不需要像 Java 或 C 语言那样还要在使用变量前声明变量的类型,但在一些特定场景中,仍然需要用到类型转换。

比如说,我们想通过使用 print() 函数输出信息“您的身高:”以及浮点类型 height 的值,如果在交互式解释器中执行如下代码:

>>> height = 70.0
>>> print("您的身高"+height)
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    print("您的身高"+height)
TypeError: must be str, not float

你会发现这是错误的,解释器提示我们字符串和浮点类型变量不能直接相连,需要提前将浮点类型变量 height 转换为字符串才可以。

庆幸的是,Python 已经为我们提供了多种可实现数据类型转换的函数,如表 1 所示。

表 1 常用数据类型转换函数

函 数

作 用

int(x)

将 x 转换成整数类型

float(x)

将 x 转换成浮点数类型

complex(real,[,imag])

创建一个复数

str(x)

将 x 转换为字符串

repr(x)

将 x 转换为表达式字符串

eval(str)

计算在字符串中的有效 Python 表达式,并返回一个对象

chr(x)

将整数 x 转换为一个字符

ord(x)

将一个字符 x 转换为它对应的整数值

hex(x)

将一个整数 x 转换为一个十六进制字符串

oct(x)

将一个整数 x 转换为一个八进制的字符串

需要注意的是,在使用类型转换函数时,提供给它的数据必须是有意义的。例如,int() 函数无法将一个非数字字符串转换成整数:

>>> int("123") #转换成功
123
>>> int("123个") #转换失败
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    int("123个")
ValueError: invalid literal for int() with base 10: '123个'
>>>

5.3 算数运算符

算术运算符也即数学运算符,用来对数字进行数学运算,比如加减乘除。下表列出了 Python 支持所有基本算术运算符。

表 1 Python 常用算术运算符

运算符

说明

实例

结果

+


12.45 + 15

27.45

-


4.56 - 0.26

4.3

*


5 * 3.6

18.0

/

除法(和数学中的规则一样)

7 / 2

3.5

//

整除(只保留商的整数部分)

7 // 2

3

%

取余,即返回除法的余数

7 % 2

1

**

幂运算/次方运算,即返回 x 的 y 次方

2 ** 4

16,即 24

接下来将对表 1 中各个算术运算符的用法逐一讲解。

5.3.1 + 加法运算符

  1. 加法运算符很简单,和数学中的规则一样,请看下面的代码:
m = 10
n = 97
sum1 = m + n
x = 7.2
y = 15.3
sum2 = x + y
print("sum1=%d, sum2=%.2f" % (sum1, sum2) )
运行结果:
sum1=107, sum2=22.50
  1. 拼接字符串
    当+用于数字时表示加法,但是当+用于字符串时,它还有拼接字符串(将两个字符串连接为一个)的作用,请看代码:
name = "Python"
url = ""
info = name + "的网址是" + url 
print(info)
运行结果:
Python的网址是

5.3.2 - 减法运算符

  1. 减法运算也和数学中的规则相同,请看代码:
n = 45
m = -n
x = -83.5
y = -x
print(m, ",", y)
运行结果:
-45 , 83.5
  1. 求负
    -除了可以用作减法运算之外,还可以用作求负运算(正数变负数,负数变正数),请看下面的代码:
n = 45
n_neg = -n
f = -83.5
f_neg = -f
print(n_neg, ",", f_neg)
运行结果:
-45 , 83.5

注意,单独使用+是无效的,不会改变数字的值,例如:

n = 45
m = +n
x = -83.5
y = +x
print(m, ",", y)
运行结果:
45 , -83.5

5.3.3 *乘法运算符

  1. 乘法运算也和数学中的规则相同,请看代码:
n = 4 * 25
f = 34.5 * 2
print(n, ",", f)
运行结果:
100 , 69.0
  1. 重复字符串
    *除了可以用作乘法运算,还可以用来重复字符串,也即将 n 个同样的字符串连接起来,请看代码:
str1 = "hello "
print(str1 * 4)
运行结果:
hello hello hello hello

5.3.4 / 和 // 除法运算符

Python 支持/和//两个除法运算符,但它们之间是有区别的:
/表示普通除法,使用它计算出来的结果和数学中的计算结果相同。
//表示整除,只保留结果的整数部分,舍弃小数部分;注意是直接丢掉小数部分,而不是四舍五入。

请看下面的例子:

#整数不能除尽
print("23/5 =", 23/5)
print("23//5 =", 23//5)
print("23.0//5 =", 23.0//5)
print("-------------------")
#整数能除尽
print("25/5 =", 25/5)
print("25//5 =", 25//5)
print("25.0//5 =", 25.0//5)
print("-------------------")
#小数除法
print("12.4/3.5 =", 12.4/3.5)
print("12.4//3.5 =", 12.4//3.5)
运行结果:
23/5 = 4.6
23//5 = 4
23.0//5 = 4.0
-------------------
25/5 = 5.0
25//5 = 5
25.0//5 = 5.0
-------------------
12.4/3.5 = 3.542857142857143
12.4//3.5 = 3.0

从运行结果可以发现:
/的计算结果总是小数,不管是否能除尽,也不管参与运算的是整数还是小数。
当有小数参与运算时,//结果才是小数,否则就是整数。

需要注意的是,除数始终不能为 0,除以 0 是没有意义的,这将导致 ZeroDivisionError 错误。在某些编程语言中,除以 0 的结果是无穷大(包括正无穷大和负无穷大)。
Python 2.x 中的除法
Python 2.x 只提供了一种除法运算,就是/,它的行为和大部分编程语言中/的行为是一样的:
当/两边都是整数时,结果始终是整数;如果不能除尽,就直接舍弃小数部分。
当/两边有一个是小数时,结果始终是小数;如果恰好除尽,小数部分就是 0。

请看下面的代码:

#整数除法
print "18/6 =", 18/6
print "47/7 =", 47/7
print "----------------"
#小数除法
print "18.0/6 =", 18.0/6
print "47.0/7 =", 47.0/7
print "29.5/4.2 =", 29.5/4.2
运行结果:
18/6 = 3
47/7 = 6
----------------
18.0/6 = 3.0
47.0/7 = 6.71428571429
29.5/4.2 = 7.02380952381

你可以将 Python 2.x 中的/看作 Python 3.x 中/和//的结合体,因为 Python 2.x 中/的行为有点奇怪,所以 Python 3.x 增加了//运算符,用以规范除法运算的行为。

5.3.5 % 求余运算符

Python % 运算符用来求得两个数相除的余数,包括整数和小数。Python 使用第一个数字除以第二个数字,得到一个整数的商,剩下的值就是余数。对于小数,求余的结果一般也是小数。

注意,求余运算的本质是除法运算,所以第二个数字也不能是 0,否则会导致 ZeroDivisionError 错误。

Python % 使用示例:

print("-----整数求余-----")
print("15%6 =", 15%6)
print("-15%6 =", -15%6)
print("15%-6 =", 15%-6)
print("-15%-6 =", -15%-6)
print("-----小数求余-----")
print("7.7%2.2 =", 7.7%2.2)
print("-7.7%2.2 =", -7.7%2.2)
print("7.7%-2.2 =", 7.7%-2.2)
print("-7.7%-2.2 =", -7.7%-2.2)
print("---整数和小数运算---")
print("23.5%6 =", 23.5%6)
print("23%6.5 =", 23%6.5)
print("23.5%-6 =", 23.5%-6)
print("-23%6.5 =", -23%6.5)
print("-23%-6.5 =", -23%-6.5)
运行结果:
-----整数求余-----
15%6 = 3
-15%6 = 3
15%-6 = -3
-15%-6 = -3
-----小数求余-----
7.7%2.2 = 1.0999999999999996
-7.7%2.2 = 1.1000000000000005
7.7%-2.2 = -1.1000000000000005
-7.7%-2.2 = -1.0999999999999996
---整数和小数运算---
23.5%6 = 5.5
23%6.5 = 3.5
23.5%-6 = -0.5
-23%6.5 = 3.0
-23%-6.5 = -3.5

从运行结果可以发现两点:
只有当第二个数字是负数时,求余的结果才是负数。换句话说,求余结果的正负和第一个数字没有关系,只由第二个数字决定。
%两边的数字都是整数时,求余的结果也是整数;但是只要有一个数字是小数,求余的结果就是小数。

5.3.6 ** 次方(乘方)运算符

Python ** 运算符用来求一个 x 的 y 次方,也即次方(乘方)运算符。
由于开方是次方的逆运算,所以也可以使用 ** 运算符间接地实现开方运算。
Python ** 运算符示例:

print('----次方运算----')
print('3**4 =', 3**4)
print('2**5 =', 2**5)
print('----开方运算----')
print('81**(1/4) =', 81**(1/4))
print('32**(1/5) =', 32**(1/5))
运行结果:
----次方运算----
3**4 = 81
2**5 = 32
----开方运算----
81**(1/4) = 3.0
32**(1/5) = 2.0

5.3.7 赋值运算符

赋值运算符用来把右侧的值传递给左侧的变量(或者常量);可以直接将右侧的值交给左侧的变量,也可以进行某些运算后再交给左侧的变量,比如加减乘除、函数调用、逻辑运算等。

  1. =赋值
    Python 中最基本的赋值运算符是等号=;结合其它运算符,=还能扩展出更强大的赋值运算符。
    基本赋值运算符
    =是 Python 中最常见、最基本的赋值运算符,用来将一个表达式的值赋给另一个变量,请看下面的例子:
#将字面量(直接量)赋值给变量
n1 = 100
f1 = 47.5
s1 = "http://c.biancheng.net/python/"
#将一个变量的值赋给另一个变量
n2 = n1
f2 = f1
#将某些运算的值赋给变量
sum1 = 25 + 46 
sum2 = n1 % 6
s2 = str(1234)  #将数字转换成字符串
s3 = str(100) + "abc"
  1. 连续赋值
    Python 中的赋值表达式也是有值的,它的值就是被赋的那个值,或者说是左侧变量的值;如果将赋值表达式的值再赋值给另外一个变量,这就构成了连续赋值。请看下面的例子:
    a = b = c = 100

=具有右结合性,我们从右到左分析这个表达式:
c = 100 表示将 100 赋值给 c,所以 c 的值是 100;同时,c = 100 这个子表达式的值也是 100。
b = c = 100 表示将 c = 100 的值赋给 b,因此 b 的值也是 100。
以此类推,a 的值也是 100。

最终结果就是,a、b、c 三个变量的值都是 100。

  1. = 和 ==
    (=) 和 (== )是两个不同的运算符,= 用来赋值,而 == 用来判断两边的值是否相等,千万不要混淆。
  2. 扩展后的赋值运算符
    =还可与其他运算符(包括算术运算符、位运算符和逻辑运算符)相结合,扩展成为功能更加强大的赋值运算符,如表 1 所示。扩展后的赋值运算符将使得赋值表达式的书写更加优雅和方便。

表 1 Python 扩展赋值运算符

运算符

说 明

用法举例

等价形式

=

最基本的赋值运算

x = y

x = y

+=

加赋值

x += y

x = x + y

-=

减赋值

x -= y

x = x - y

*=

乘赋值

x *= y

x = x * y

/=

除赋值

x /= y

x = x / y

%=

取余数赋值

x %= y

x = x % y

**=

幂赋值

x **= y

x = x ** y

//=

取整数赋值

x //= y

x = x // y

&=

按位与赋值

x &= y

x = x & y

I=

按位或赋值

xI= y

x = x Iy

^=

按位异或赋值

x ^= y

x = x ^ y

<<=

左移赋值

x <<= y

x = x << y,这里的 y 指的是左移的位数

>>=

右移赋值

x >>= y

x = x >> y,这里的 y 指的是右移的位数

这里举个简单的例子:

n1 = 100
f1 = 25.5
n1 -= 80  #等价于 n1=n1-80
f1 *= n1 - 10 #等价于 f1=f1*( n1 - 10 )
print("n1=%d" % n1)
print("f1=%.2f" % f1)
运行结果为:
n1=20
f1=255.00

通常情况下,只要能使用扩展后的赋值运算符,都推荐使用这种赋值运算符。

但是请注意,这种赋值运算符只能针对已经存在的变量赋值,因为赋值过程中需要变量本身参与运算,如果变量没有提前定义,它的值就是未知的,无法参与运算。例如,下面的写法就是错误的:

n += 10

该表达式等价于 n = n + 10,n 没有提前定义,所以它不能参与加法运算。

5.3.8 位运算符

Python 位运算按照数据在内存中的二进制位(Bit)进行操作,它一般用于底层开发(算法设计、驱动、图像处理、单片机等),在应用层开发(Web 开发、Linux 运维等)中并不常见。想加快学习进度,或者不关注底层开发的读者可以先跳过本节,以后需要的话再来学习。

Python 位运算符只能用来操作整数类型,它按照整数在内存中的二进制形式进行计算。Python 支持的位运算符如表 1 所示。

表 1 Python 位运算符一览表

位运算符

说明

使用形式

举 例

&

按位与

a & b

4 & 5

I

按位或

a Ib

4 I5

^

按位异或

a ^ b

4 ^ 5

~

按位取反

~a

~4

<<

按位左移

a << b

4 << 2,表示整数 4 按位左移 2 位

>>

按位右移

a >> b

4 >> 2,表示整数 4 按位右移 2 位

5.3.8.1 & 按位与运算符

按位与运算符&的运算规则是:只有参与&运算的两个位都为 1 时,结果才为 1,否则为 0。例如1&1为 1,0&0为 0,1&0也为 0,这和逻辑运算符&&非常类似。

表 2 Python & 运算符的规则

第一个Bit位

第二个Bit位

结果

0

0

0

0

1

0

1

0

0

1

1

1

例如,9&5可以转换成如下的运算:

0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (9 在内存中的存储)
& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-----------------------------------------------------------------------------------
  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0001  (1 在内存中的存储)
&运算符会对参与运算的两个整数的所有二进制位进行&运算,9&5的结果为 1。

又如,-9&5可以转换成如下的运算:
  1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
& 0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-----------------------------------------------------------------------------------
  0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 0101  (5 在内存中的存储)
-9&5的结果是 5。

再强调一遍,&运算符操作的是数据在内存中存储的原始二进制位,而不是数据本身的二进制形式;其他位运算符也一样。以-9&5为例,-9 的在内存中的存储和 -9 的二进制形式截然不同:

1111 1111 -- 1111 1111 -- 1111 1111 -- 1111 0111  (-9 在内存中的存储)
-0000 0000 -- 0000 0000 -- 0000 0000 -- 0000 1001  (-9 的二进制形式,前面多余的0可以抹掉)

按位与运算通常用来对某些位清 0,或者保留某些位。例如要把 n 的高 16 位清 0 ,保留低 16 位,可以进行n & 0XFFFF运算(0XFFFF 在内存中的存储形式为 0000 0000 – 0000 0000 – 1111 1111 – 1111 1111)。

5.3.8.2 | 按位或运算符

按位或运算符|的运算规则是:两个二进制位有一个为 1 时,结果就为 1,两个都为 0 时结果才为 0。例如1|1为 1,0|0为0,1|0 为1,这和逻辑运算中的||非常类似。

按位或运算可以用来将某些位置 1,或者保留某些位。例如要把 n 的高 16 位置 1,保留低 16 位,可以进行n | 0XFFFF0000运算(0XFFFF0000 在内存中的存储形式为 1111 1111 – 1111 1111 – 0000 0000 – 0000 0000)。

5.3.8.3 ^按位异或运算符

按位异或运算^的运算规则是:参与运算的两个二进制位不同时,结果为 1,相同时结果为 0。
例如:
0^1为 1,
0^0为 0,
1^1为 0。

按位异或运算可以用来将某些二进制位反转。例如要把 n 的高 16 位反转,保留低 16 位,可以进行n ^ 0XFFFF0000运算(0XFFFF0000 在内存中的存储形式为 1111 1111 – 1111 1111 – 0000 0000 – 0000 0000)。

5.3.8.4 ~按位取反运算符

按位取反运算符为单目运算符(只有一个操作数),右结合性,作用是对参与运算的二进制位取反。例如1为0,~0为1,这和逻辑运算中的!非常类似。

5.3.8.5 <<左移运算符

Python 左移运算符<<用来把操作数的各个二进制位全部左移若干位,高位丢弃,低位补 0。

如果数据较小,被丢弃的高位不包含 1,那么左移 n 位相当于乘以 2 的 n 次方。

5.3.8.6 >>右移运算符

Python 右移运算符>>用来把操作数的各个二进制位全部右移若干位,低位丢弃,高位补 0 或 1。如果数据的最高位是 0,那么就补 0;如果最高位是 1,那么就补 1。

如果被丢弃的低位不包含 1,那么右移 n 位相当于除以 2 的 n 次方(但被移除的位中经常会包含 1)。

5.3.9 比较运算符(关系运算符)

比较运算符,也称关系运算符,用于对常量、变量或表达式的结果进行大小比较。如果这种比较是成立的,则返回 True(真),反之则返回 False(假)。
True 和 False 都是 bool 类型,它们专门用来表示一件事情的真假,或者一个表达式是否成立.

Python 支持的比较运算符如表 1 所示。

表 1 Python 比较运算符汇总

比较运算符

说明

>

大于,如果>前面的值大于后面的值,则返回 True,否则返回 False。

<

小于,如果<前面的值小于后面的值,则返回 True,否则返回 False。

==

等于,如果==两边的值相等,则返回 True,否则返回 False。

>=

大于等于(等价于数学中的 ≥),如果>=前面的值大于或者等于后面的值,则返回 True,否则返回 False。

<=

小于等于(等价于数学中的 ≤),如果<=前面的值小于或者等于后面的值,则返回 True,否则返回 False。

!=

不等于(等价于数学中的 ≠),如果!=两边的值不相等,则返回 True,否则返回 False。

is

判断两个变量所引用的对象是否相同,如果相同则返回 True,否则返回 False。

is not

判断两个变量所引用的对象是否不相同,如果不相同则返回 True,否则返回 False。

Python 比较运算符的使用举例:

print("89是否大于100:", 89 > 100)
print("24*5是否大于等于76:", 24*5 >= 76)
print("86.5是否等于86.5:", 86.5 == 86.5)
print("34是否等于34.0:", 34 == 34.0)
print("False是否小于True:", False < True)
print("True是否等于True:", True < True)
运行结果:
89是否大于100: False
24*5是否大于等于76: True
86.5是否等于86.5: True
34是否等于34.0: True
False是否小于True: True
True是否等于True: False

== 和 is 的区别
初学 Python,大家可能对 is 比较陌生,很多人会误将它和 == 的功能混为一谈,但其实 is 与 == 有本质上的区别,完全不是一码事儿。

== 用来比较两个变量的值是否相等,而 is 则用来比对两个变量引用的是否是同一个对象,例如:

import time  #引入time模块
t1 = time.gmtime() # gmtime()用来获取当前时间
t2 =  time.gmtime()
print(t1 == t2) #输出True
print(t1 is t2) #输出False
运行结果:
True
False

time 模块的 gmtime() 方法用来获取当前的系统时间,精确到秒级,因为程序运行非常快,所以 t1 和 t1 得到的时间是一样的。== 用来判断 t1 和 t2 的值是否相等,所以返回 True。

虽然 t1 和 t2 的值相等,但它们是两个不同的对象(每次调用 gmtime() 都返回不同的对象),所以t1 is t2返回 False。这就好像两个双胞胎姐妹,虽然她们的外貌是一样的,但它们是两个人。

那么,如何判断两个对象是否相同呢?答案是判断两个对象的内存地址。如果内存地址相同,说明两个对象使用的是同一块内存,当然就是同一个对象了;这就像两个名字使用了同一个身体,当然就是同一个人了。

5.3.10 逻辑运算符

高中数学中我们就学过逻辑运算,例如 p 为真命题,q 为假命题,那么“p且q”为假,“p或q”为真,“非q”为真。Python 也有类似的逻辑运算,请看下表:

表 1 Python 逻辑运算符及功能

逻辑运算符

含义

基本格式

说明

and

逻辑与运算,等价于数学中的“且”

a and b

当 a 和 b 两个表达式都为真时,a and b 的结果才为真,否则为假。

or

逻辑或运算,等价于数学中的“或”

a or b

当 a 和 b 两个表达式都为假时,a or b 的结果才是假,否则为真。

not

逻辑非运算,等价于数学中的“非”

not a

如果 a 为真,那么 not a 的结果为假;如果 a 为假,那么 not a 的结果为真。相当于对 a 取反。

逻辑运算符一般和关系运算符结合使用,例如:

14>6 and 45.6 > 90

14>6 结果为 True,成立,45.6>90 结果为 False,不成立,所以整个表达式的结果为 False,也即不成立。

再看一个比较实用的例子:

age = int(input("请输入年龄:"))
height = int(input("请输入身高:"))
if age>=18 and age<=30 and height >=170 and height <= 185 :
    print("恭喜,你符合报考飞行员的条件")
else:
    print("抱歉,你不符合报考飞行员的条件")
可能的运行结果:
请输入年龄:23↙
请输入身高:178↙
恭喜,你符合报考飞行员的条件

Python 逻辑运算符可以用来操作任何类型的表达式,不管表达式是不是 bool 类型;同时,逻辑运算的结果也不一定是 bool 类型,它也可以是任意类型。请看下面的例子:

print(100 and 200)
print(45 and 0)
print("" or "")
print(18.5 or "")
运行结果:
200
0

18.5

你看,本例中 and 和 or 运算符操作的都不是 bool 类型表达式,操作的结果也不是 bool 值。
逻辑运算符的本质
在 Python 中,and 和 or 不一定会计算右边表达式的值,有时候只计算左边表达式的值就能得到最终结果。

另外,and 和 or 运算符会将其中一个表达式的值作为最终结果,而不是将 True 或者 False 作为最终结果。

以上两点极其重要,了解这两点不会让你在使用逻辑运算的过程中产生疑惑。

对于 and 运算符,两边的值都为真时最终结果才为真,但是只要其中有一个值为假,那么最终结果就是假,所以 Python 按照下面的规则执行 and 运算:
如果左边表达式的值为假,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是假,此时 and 会把左边表达式的值作为最终结果。
如果左边表达式的值为真,那么最终值是不能确定的,and 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。

对于 or 运算符,情况是类似的,两边的值都为假时最终结果才为假,只要其中有一个值为真,那么最终结果就是真,所以 Python 按照下面的规则执行 or 运算:
如果左边表达式的值为真,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是真,此时 or 会把左边表达式的值作为最终结果。
如果左边表达式的值为假,那么最终值是不能确定的,or 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。

5.3.11 三目运算符(三元运算符)

我们从一个具体的例子切入本节内容。假设现在有两个数字,我们希望获得其中较大的一个,那么可以使用 if else 语句,例如:

if a>b:
    max = a;
else:
    max = b;
    ```
但是 Python 提供了一种更加简洁的写法,如下所示:
```markdown
max = a if a>b else b

这是一种类似于其它编程语言中三目运算符? :的写法。Python 是一种极简主义的编程语言,它没有引入? :这个新的运算符,而是使用已有的 if else 关键字来实现相同的功能。

使用 if else 实现三目运算符(条件运算符)的格式如下:

exp1 if contion else exp2

condition 是判断条件,exp1 和 exp2 是两个表达式。如果 condition 成立(结果为真),就执行 exp1,并把 exp1 的结果作为整个表达式的结果;如果 condition 不成立(结果为假),就执行 exp2,并把 exp2 的结果作为整个表达式的结果。

前面的语句max = a if a>b else b的含义是:
如果 a>b 成立,就把 a 作为整个表达式的值,并赋给变量 max;
如果 a> b 不成立,就把 b 作为整个表达式的值,并赋给变量 max。
三目运算符的嵌套
Python 三目运算符支持嵌套,如此可以构成更加复杂的表达式。在嵌套时需要注意 if 和 else 的配对,例如:

a if a>b else c if c>d else d

应该理解为:

a if a>b else ( c if c>d else d )

【实例】使用 Python 三目运算符判断两个数字的关系:

a = int( input("Input a: ") )
b = int( input("Input b: ") )
print("a大于b") if a>b else ( print("a小于b") if a<b else print("a等于b") )
可能的运行结果:
Input a: 45↙
Input b: 100↙
a小于b

该程序是一个嵌套的三目运算符。程序先对 a>b 求值,如果该表达式为 True,程序就返回执行第一个表达式 print(“a大于b”),否则将继续执行 else 后面的内容,也就是:

( print("a小于b") if a<b else print("a等于b") )

进入该表达式后,先判断 a<b 是否成立,如果 a<b 的结果为 True,将执行 print(“a小于b”),否则执行 print(“a等于b”)。

5.3.12 运算符优先级和结合性一览表

优先级和结合性是 Python 表达式中比较重要的两个概念,它们决定了先执行表达式中的哪一部分。
Python 运算符优先级
所谓优先级,就是当多个运算符同时出现在一个表达式中时,先执行哪个运算符。

例如对于表达式a + b * c,Python 会先计算乘法再计算加法;b * c的结果为 8,a + 8的结果为 24,所以 d 最终的值也是 24。先计算再计算+,说明的优先级高于+。

Python 支持几十种运算符,被划分成将近二十个优先级,有的运算符优先级不同,有的运算符优先级相同,请看下表。
数值越大,优先级越高。
表 1 Python 运算符优先级和结合性一览表

运算符说明

Python运算符

优先级

结合性

小括号

( )

19


索引运算符

x[i] 或 x[i1: i2 [:i3]]

18


属性访问

x.attribute

17


乘方

**

16


按位取反

~

15


符号运算符

+(正号)、-(负号)

14


乘除

*、/、//、%

13


加减

+、-

12


位移

>>、<<

11


按位与

&

10


按位异或

^

9


按位或

I

8


比较运算符

==、!=、>、>=、<、<=

7


is

运算符

is、is not

6

in

运算符

in、not in

5

逻辑非

not

4


逻辑与

and

3


逻辑或

or

2


逗号运算符

exp1, exp2

1


结果表1中的运算符优先级,我们尝试分析下面表达式的结果:

4+4<<2

+的优先级是 12,<<的优先级是 11,+的优先级高于<<,所以先执行 4+4,得到结果 8,再执行 8<<2,得到结果 32,这也是整个表达式的最终结果。

像这种不好确定优先级的表达式,我们可以给子表达式加上( ),也就是写成下面的样子:
(4+4) << 2

这样看起来就一目了然了,不容易引起误解。

当然,我们也可以使用( )改变程序的执行顺序,比如:
4+(4<<2)

则先执行 4<<2,得到结果 16,再执行 4+16,得到结果20。

虽然 Python 运算符存在优先级的关系,但我不推荐过度依赖运算符的优先级,这会导致程序的可读性降低。因此,我建议读者:
不要把一个表达式写得过于复杂,如果一个表达式过于复杂,可以尝试把它拆分来书写。
不要过多地依赖运算符的优先级来控制表达式的执行顺序,这样可读性太差,应尽量使用( )来控制表达式的执行顺序。

  • Python 运算符结合性
    所谓结合性,就是当一个表达式中出现多个优先级相同的运算符时,先执行哪个运算符:先执行左边的叫左结合性,先执行右边的叫右结合性。

例如对于表达式对于100 / 25 * 16,/和的优先级相同,应该先执行哪一个呢?这个时候就不能只依赖运算符优先级决定了,还要参考运算符的结合性。/和都具有左结合性,因此先执行左边的除法,再执行右边的乘法,最终结果是 64。

Python 中大部分运算符都具有左结合性,也就是从左到右执行;只有 ** 乘方运算符、单目运算符(例如 not 逻辑非运算符)、赋值运算符和三目运算符例外,它们具有右结合性,也就是从右向左执行。表 1 中列出了所有 Python 运算符的结合性。
总结
当一个表达式中出现多个运算符时,Python 会先比较各个运算符的优先级,按照优先级从高到低的顺序依次执行;当遇到优先级相同的运算符时,再根据结合性决定先执行哪个运算符:如果是左结合性就先执行左边的运算符,如果是右结合性就先执行右边的运算符。