购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.3 运算符

在计算机中,数据处理实际上就是对数据按照一定的规则进行运算。在已经掌握Python基本数据类型的基础上,下面来看一下对这些类型的数据可以做哪些运算。这里介绍数据处理中一些常用运算符的作用和使用方法。

2.3.1 占位运算符

占位运算符类似于C语言中sprintf或printf函数中使用的占位符,在字符串中可以给出一些占位符来表示不同类型的数据,而实际的数据值在字符串之外给出。此处仅介绍3个常用占位符(如表2-2所示),更多的占位符信息将在第6章中给出。

表1-2 Python部分版本的信息

下面通过具体示例介绍这3个占位符的使用方法,如代码清单2-12所示。

表1-2 Python部分版本的信息

代码清单2-12执行完毕后,可得到如图2-25所示的结果。

图2-25 代码清单2-12的运行结果

从输出结果中可以看出占位符的使用方法和使用上的差异:

• 在带有占位符的字符串后面写上%(…),即可在一对圆括号中指定前面字符串中各占位符所对应的实际数据值,各数据值之间用逗号分开。例如,对于代码清单2-12中的第1~3行代码,因为前面的字符串中包含4个占位符(%s、%d、%d和%f),所以后面%(…)的一对圆括号中给出了用逗号分隔的4个对应的数据值。

• 对于占位符%s,可以写成%xs的形式(其中x是一个整数),x用于指定代入字符串所占的字符数。如果未指定x,或者x小于或等于实际代入字符串的长度,则将字符串直接代入;如果x大于实际代入字符串的长度,则会在代入的字符串前面补空格,使得实际代入字符串的长度为x。例如,对于代码清单2-12中的第2行和第3行代码,%5s要求代入的字符串占5个字符的空间,但实际代入的字符串"小明"的长度为2,所以会在“小明”前补3个空格。

• 对于占位符%d,可以写成%xd或%0xd的形式(其中x是一个整数),x用于指定代入整数的位数。如果未指定x,或者x小于或等于实际代入整数的位数,则将整数直接代入;如果x大于实际代入整数的位数,则会在代入的整数前面补空格(%xd)或0(%0xd),使得实际代入整数的位数是x。例如,对于代码清单2-12中的第2行和第3行代码,%5d和%05d要求代入的整数是5位,但实际代入的整数85和90的位数都为2,所以分别在85和90前补3个空格或3个0。

• 对于占位符%f,可以写成%.yf、%x.yf或%0x.yf的形式(其中x和y都是整数),x用于指定代入浮点数的位数,y用于指定代入浮点数的小数位数。如果未指定x,或者x小于或等于实际代入浮点数的位数,则将浮点数直接代入;如果x大于实际代入浮点数的位数,则会在代入的整数前面补空格(%x.yf)或0(%0x.yf),使得实际代入浮点数的位数是x。如果未指定y,则默认保留6位小数;否则,由y决定小数位数,代入浮点数的实际小数位数小于y时,则在后面补0。例如,对于代码清单2-12中的第2行代码,%.2f指定小数位数为2,因此实际代入的浮点数为0.06(保留两位小数);对于第3行代码,%08.2f指定代入浮点数的位数为8,不足补0,小数位数为2,因此实际代入的浮点数为00000.06。

提示 由于%作为占位符的前缀字符,因此对于有占位符的字符串,表示一个%时需要写成%%。例如,执行print('优秀比例为%.2f%%,良好比例为%.2f%%。'%(5.2, 20.35)),输出结果为“优秀比例为5.20%,良好比例为20.35%。”如图2-26所示。

图2-26 有占位符的字符串中表示%的方法

【思考题2-21】 下列占位运算符中,表示有符号整型十进制数的占位符是( )。

A.%d

B.%%

C.%f

D.%s

2.3.2 算术运算符

算术运算是计算机支持的主要运算之一,其运算对象是数值型数据。Python中的算术运算符如表2-3所示。

表1-2 Python部分版本的信息

这里通过代码清单2-13理解各算术运算符的作用和使用方法。

表1-2 Python部分版本的信息

代码清单2-13执行完毕后,第4~12行代码分别按对应注释中的描述输出结果,如图2-27所示。

图2-27 代码清单2-13的运行结果

提示 计算机实际存储数据时使用二进制方式,我们在输入和查看数据时使用十进制方式,这就涉及二进制和十进制的转换。

在将输入的十进制数据保存在计算机中时,系统会自动做十进制转二进制的操作,然后将转换后的二进制数据保存;当我们查看计算机中保存的数据时,系统会将保存的二进制数据转成十进制,再显示出来。

然而,十进制小数在转换为二进制时有可能产生精度损失,所以在代码清单2-13第6行和第7行的输出中,结果与实际计算结果之间存在偏差,如f1(值为3.2)乘以f2(值为1.5)应该等于4.8,但最后输出的数据与实际计算结果存在0.000000000000001的偏差。

【思考题2-22】 3**4的运算结果为( )。

A.12

B.81

C.7

D.报错

2.3.3 赋值运算符

赋值运算要求左操作数对象必须是值可以修改的变量,Python中的赋值运算符如表2-4所示。

表1-2 Python部分版本的信息

这里通过代码清单2-14理解赋值运算符的作用和使用方法。

表1-2 Python部分版本的信息

代码清单2-14执行完毕后,第3、6、9、12行代码分别按对应注释中的描述输出结果,如图2-28所示。读者可在Python环境中尝试其他赋值运算符的具体使用。

图2-28 代码清单2-14的运行结果

代码清单2-14中部分代码的描述如下。

• 第2行代码i1+=i2等价于i1=i1+i2,即先将i1和i2的值做加法运算,再将运算结果赋值给i1。

• 第5行代码c1-=c2等价于c1=c1-c2,即先将c1和c2的值做减法运算,再将运算结果赋值给c1。

• 第8行代码f1*=f2等价于f1=f1*f2,即先将f1和f2的值做乘法运算,再将运算结果赋值给f1。

• 第11行代码i1**=f1等价于i1=i1**f1,即先将i1和f1的值做幂运算,再将运算结果赋值给i1。

【思考题2-23】 已知a=15,则执行“a%=6”后,a的值为( )。

A.15

B.2.5

C.3

D.2

2.3.4 比较运算符

比较运算的作用是对两个操作数对象的大小关系进行判断,Python中的比较运算符如表2-5所示。

表1-2 Python部分版本的信息

(续)

这里通过代码清单2-15理解各比较运算符的作用和使用方法。

表1-2 Python部分版本的信息

代码清单2-15执行完毕后,第2~7行代码分别按对应注释中的描述输出结果,如图2-29所示。

图2-29 代码清单2-15的运行结果

提示 比较运算返回的结果是布尔值True或False。在执行程序时,程序中的每条语句并不一定按顺序依次执行。比较运算的主要作用是设置条件,某些语句在满足条件时才会执行一次(即条件语句),而某些语句在满足条件时会重复执行多次(即循环语句)。本章后面会详细介绍这两种语句的实现方法。

注意 区分赋值运算符=(一个等号)和比较运算符==(两个等号)。例如,a=5表示通过赋值运算将数值5赋给变量a;而a==5用于判断变量a是否等于5,返回True或False。

2.3.5 逻辑运算符

逻辑运算可以将多个比较运算连接起来形成更复杂的条件判断,Python中的逻辑运算符如表2-6所示。

表1-2 Python部分版本的信息

这里通过代码清单2-16理解各逻辑运算符的作用和使用方法。

表1-2 Python部分版本的信息

代码清单2-16执行完毕后,第2~4行代码分别按对应注释中的描述输出结果,如图2-30所示。

图2-30 代码清单2-16的运行结果

代码清单2-16中第2~4行代码的描述如下。

• 第2行代码中,n>=0 and n<=a使用逻辑与运算符and连接了两个比较运算。前面的比较运算n>=0用于判断n是否大于或等于0;后面的比较运算n<=a用于判断n是否小于或等于a。当两个比较运算都成立(即都返回True)时,逻辑与运算结果为True;当至少有一个比较运算不成立(即其中一个比较运算返回False或两个比较运算都返回False)时,逻辑与运算结果为False。变量n和a的值分别是80和100,n>=0和n<=a这两个比较运算都成立,因此逻辑与运算的结果为True。

• 第3行代码中,n<0 or n>a使用逻辑或运算符or连接了两个比较运算。前面的比较运算n<0用于判断n是否小于0;后面的比较运算n>a用于判断n是否大于a。当至少有一个比较运算成立(即其中一个比较运算返回True或两个比较运算都返回True)时,逻辑或运算结果为True;当两个比较运算都不成立(即都返回False)时,逻辑或运算结果为False。变量n和a的值分别是80和100,n<0和n>a这两个比较运算都不成立,因此逻辑或运算的结果为False。

• 第4行代码中,not(n>=0 and n<=a)对n>=0 and n<=a的结果做逻辑非运算。根据第2行代码的描述,n>=0 and n<=a的返回结果是True,因此逻辑非运算的结果为False。

提示

1.逻辑运算的运算数是布尔型数据,返回结果也是布尔型数据。使用逻辑运算符可以将多个比较运算连接起来,形成更复杂的条件。

2.代码清单2-16第2行代码中的n>=0 and n<=a也可以写为0<=n<=a,二者完全等价。

【思考题2-24】 下列选项中,可以用于判断c中保存的字符是否是英文字母的表达式是( )。

A.c>='a' and c<='Z'

B.c>='A' and c<='z'

C.(c>='a' and c<='z') and (c>='A' and c<='Z')

D.(c>='a' and c<='z') or (c>='A' and c<='Z')

2.3.6 位运算符

位运算是指对二进制数进行逐位运算,因此在给出各位运算符的功能前,先介绍十进制数和二进制数的相互转换方法。由于位运算符要求运算数必须是整数,所以这里只给出整数的转换规则,小数的转换规则读者可参阅其他资料。

十进制整数转换为二进制数采用“除基取余法”:用2去除十进制整数,得到商和余数;如果商不为0,则继续用2除,再得到商和余数,重复该步骤直至商为0;最后将余数按照从后至前的顺序排列,即得到转换后的十进制数。

提示 “除基取余法”中的“基”是指基数,基数即一种数制中可用数码的个数。二进制可用的数码只有0和1两个,所以二进制的基数是2。

下面以26转换为二进制数为例说明“除基取余法”的具体步骤。如图2-31所示,首先,用26除以2,商13,余0。然后,对得到的商不断用2除,直至商为0,依次得到如下结果:商6,余1;商3,余0;商1,余1;商0,余1。最后,将得到的余数按照从后向前的顺序排列,得到最后的转换结果,即11010B(以B作为后缀表示这是一个二进制数)。

图2-31 十进制整数转二进制数示例

二进制数转十进制数的规则是“按权展开求和”,即将二进制数的每一位写成数码乘以位权的形式,再对乘积求和。例如,对于二进制数11010B,其对应的十进制数为

11010B=1×2 4 +1×2 3 +0×2 2 +1×2 1 +0×2 0

=1×16+1×8+0×4+1×2+0×1

=16+8+0+2+0

=26

提示 对于任何一种数制,一个数码在不同的位上所表示的值大小不同,它的值等于数码乘以该数码所在位的位权。位权是基数的整数次幂,小数点左边第一位的位权是基数的0次幂,左边第二位的位权是基数的1次幂,依此类推。

例如,十进制数的基数是10,因此对于十进制数333,百位上的3表示300(3×10 2 ),而十位和个位上的3分别表示30(3×10 1 )和3(3×10 0 )。再例如,二进制数的基数是2,因此对于二进制数11010B,从左到右的3个“1”所表示的值分别是16(1×2 4 )、8(1×2 3 )和2(1×2 1 )。

Python中的位运算符如表2-7所示。

表1-2 Python部分版本的信息

这里通过代码清单2-17理解位运算符的作用和使用方法。

表1-2 Python部分版本的信息

代码清单2-17执行完毕后,第2~6行代码分别按对应注释中的描述输出结果,如图2-32所示。

图2-32 代码清单2-17的运行结果

这里以第2行代码为例说明位运算的具体方法:

• 将i1和i2的值分别转换为二进制数,得到11B和110B;

• 按小数点将两个运算数对齐,缺少的位补0,因此i1表示为011B,i2仍表示为110B;

• 对每一个二进制位分别做“与”运算,两个运算数只有从右数第2位的值都为1,所以运算结果中只有从右数第2位的值为1,其他位的值均为0;

• 将按位与运算结果010B转换为十进制数,得到2。

【思考题2-25】 十进制数37转为二进制数的结果为( )。

A.100101B

B.101001B

C.100100B

D.100001B

【思考题2-26】 7^10的运算结果为(

A.17

B.15

C.13

D.2

2.3.7 身份运算符

身份运算用于比较两个对象是否对应同样的存储单元,Python的身份运算符如表2-8所示。

表1-2 Python部分版本的信息

提示 程序在运行时,输入数据和输出数据都存放在内存中。内存中的一个存储单元可以存储一个字节的数据,每个存储单元都有一个唯一的编号,称为内存地址。根据数据类型不同,数据所占用的内存大小也不同。一个数据通常会占据内存中连续多个存储单元,起始存储单元的地址称为该数据的内存首地址。利用id函数可以查看一个数据的内存首地址。

x is y等价于id(x)==id(y),即判断x和y的内存首地址是否相同;x is not y等价于id(x)!=id(y),即判断x和y的内存首地址是否不同。

这里通过代码清单2-18理解身份运算符的作用和使用方法。

表1-2 Python部分版本的信息

代码清单2-18执行完毕后,第2~4、6~8、10行代码分别按对应注释中的描述输出结果,如图2-33所示。

图2-33 代码清单2-18的运行结果

根据输出结果可以得到以下信息:

• 从第2~4行代码的输出结果可以看到,对于数值类型的数据,无论它是常量还是变量,只要其值相同,就对应相同的存储单元。

• 从第6~8行代码的输出结果可以看到,对于列表类型的数据,无论它是常量还是变量,虽然它们的值相同,但对应的存储单元不同。因此,第6行和第8行中的is运算都会返回False。而比较运算符==只是单纯进行值的比较,只要值相等就会返回True(如第7行代码)。

• 如果赋值运算符=的右操作数也是一个变量,则赋值运算后左操作数变量和右操作数变量会对应相同的存储单元(如第10行代码)。

提示 在前面学习的6种Python基本数据类型中,需要关注列表、集合、字典这3种类型的数据对象是否对应相同的存储单元,以避免对元素的意外修改。

例如,如图2-34所示,对于列表y=[1, 2, 3],执行x=y,则x和y对应相同的存储单元。此时,如果执行x[1]=20,将列表x中索引值为1的元素由2改为20,则列表y中的元素也会同时改变。出现这种结果的原因在于:通过赋值运算x=y,并不会创建新的列表,而是使x和y对应了同一个已有的列表。后面章节中,会介绍根据一个已有列表创建一个新列表的方法。

图2-34 对应相同存储单元的列表的操作示例

【思考题2-27】 程序在运行时,输入数据和输出数据都存放在( )中。

A.外存

B.内存

C.CPU

D.硬盘

2.3.8 成员运算符

成员运算用于判断一个可迭代对象(如序列、集合、字典)中是否包含某个元素,Python中的成员运算符如表2-9所示。

表1-2 Python部分版本的信息

提示 对于字符串,可以使用in或not in判断一个字符串是否是另一个字符串的子串。

这里通过代码清单2-19理解成员运算符的作用和使用方法。

表1-2 Python部分版本的信息

代码清单2-19执行完毕后,第2、4、6、8、10、12、13行代码分别按对应注释中的描述输出结果,如图2-35所示。

图2-35 代码清单2-19的运行结果

提示

1.代码清单2-19的第8行代码中,x和y是两个字符串'Py'和'Python'。因此,通过x in y,可以判断x是否是y的子串。'Py'是'Python'的子串,所以结果为True。

2.使用成员运算符判断一个数据是否是字典中的元素,实际上就是判断该数据是否是字典中某个元素的键。如代码清单2-19的第12和13行代码所示,'one'是y中第一个元素的键,因此x in y返回True;而1虽然是y中第一个元素的值,但不是任何一个元素的键,因此1 in y返回False。

【思考题2-28】 下列选项中,返回结果为True的表达式为( )。

A.1 in {'ab':1}

B.'ab' in 'abc'

C.'ac' in 'abc'

D.'ab' in ['abc', 1]

2.3.9 序列运算符

这里介绍两个用于序列的运算符:+和*,如表2-10所示。

表1-2 Python部分版本的信息

这里通过代码清单2-20理解序列运算符的作用和使用方法。

表1-2 Python部分版本的信息

代码清单2-20执行完毕后,第3、6、8、10行代码分别按对应注释中的描述输出结果,如图2-36所示。

图2-36 代码清单2-20的运行结果

代码清单2-20中部分代码的描述如下。

• 第2行代码中,x和y是第1行代码中创建的两个列表变量,值分别是[12, False]和['abc', 15, True]。因此,x+y中的“+”表示序列的拼接运算,而不是数值的加法运算,其会创建一个新列表,该新列表包含了x和y中的元素,其值为[12, False, 'abc', 15, True]。

• 第5行代码中,s1和s2是第4行代码中创建的两个字符串变量,值分别是'我喜欢学习'和'Python'。执行s1+s2,则会进行两个字符串的拼接运算,创建一个新的字符串,其值为'我喜欢学习Python'。

• 第7行代码中,x是第1行代码中创建的列表变量,其值为[12, False]。因此,x*3中的“*”表示序列的重复运算,而不是数值的乘法运算,其会将列表x中的元素重复3次,创建一个新列表,该新列表的值为[12, False, 12, False, 12, False]。

• 第9行代码中,s是第5行代码中通过字符串拼接运算创建的字符串变量,其值为'我喜欢学习Python'。执行s*3,则会执行字符串的重复运算,将字符串s中的元素重复3次,创建一个新字符串,该新字符串的值为'我喜欢学习Python我喜欢学习Python我喜欢学习Python'。

2.3.10 运算符优先级

在一个表达式中,通常会包含多个运算,这就涉及运算的顺序,其由两个因素确定:运算符的优先级和运算符的结合性。

• 对于具有不同优先级的运算符,会先完成高优先级的运算,再完成低优先级的运算。例如,表达式3+5*6中,“*”的优先级高于“+”,因此先计算5*6,得到30,再计算3+30。

• 对于具有相同优先级的运算符,其运算顺序由结合性来决定。结合性包括左结合和右结合两种:左结合是按照从左向右的顺序完成计算,而右结合是按照从右向左的顺序完成计算。例如,表达式5-3+6中,“-”和“+”的优先级相同,它们是左结合的运算符,因此先计算5-3,得到2,再计算2+6;表达式a=b=1中,“=”是右结合的运算符,因此先计算b=1,再计算a=b。

前面所介绍的各运算符的优先级如表2-11所示。优先级的值越小,则表示优先级越高。

表1-2 Python部分版本的信息

提示 如果不确定优先级和结合性,或者希望不按优先级和结合性规定的顺序完成计算,可以使用圆括号改变计算顺序。例如,对于3+5*6,如果希望先算“+”,再算“*”,则可以写为(3+5)*6。

【思考题2-29】 3*5**2的运算结果为( )。

A.30

B.225

C.75

D.报错

【思考题2-30】 已知x=5,则执行“x*=3+6”后,x的值为( )。

A.15

B.21

C.45

D.报错

【思考题2-31】 表达式a=b=1中两个运算符的运算顺序是否是从右至左? Hlo7NKdyXDbles3HrxQ6HCGLm6r8UGWPIgGHYZhx5v7bxyiBcn5n2D4VhxX1m5zr

点击中间区域
呼出菜单
上一章
目录
下一章
×