Python3从入门到实战
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.5 运算符和表达式

2.5.1 运算符和表达式的应用方法

程序就是对数据进行处理,表示数据的值(对象)可以用变量给它们起名字(用变量名引用这些值(对象)),对这些变量或值进行处理可使用一些特殊的符号如+、*等进行加法、乘法等运算,这些表示不同运算功能的特殊符号称为运算符(operators)。这些运算符操作的变量或值称为“运算数(operands)”。例如:

2+3
3/(5+2)
3*"world"

用+、/、*、(、)这些运算符对运算数进行运算的式子就是表达式(expression),即表达式是由运算数(值、变量、对象)和运算符构造的。

因为这些表示运算的运算符来自人们熟悉的符号,用它们构成的表达式的含义都很清楚。

前面介绍过,不同类型的对象支持的运算符是不同的,如不能对2个str字符串类型的变量应用-、*、/、//等运算,也不能对1个字符串和1个整数进行如-、+、/等运算。例如,下面的都是非法的:

'hi'-1 'Hello'/123 'hi'*'Hello' '15'+2

即使可以对2个字符串应用+运算符,其含义也不同于2个整数的加法运算,而实际是对2个字符串进行拼接。同样,对1个字符串和1个整数可以应用乘法运算符*,其含义是产生一个重复复制的字符串。例如:

s1="hello"
s2=s1+"world"
s3 =3*"world"
print(s2)
print(s3)

输出:

helloworld
worldworldworld

不同运算符具有不同的优先级和结合性。例如:

3+5/2    #优先级:先乘除后加减
3+5-2    #结合性:从左向右计算

“3+5/2”中运算符/优先于+,“3+5-2”中+和-具有同样的优先级,但它们的结合性都是“从左向右”,因此,先计算左边的+,再计算右边的-。

2.5.2 运算符的种类

和其他编程语言一样,Python有不同功能的各种运算符,如进行数学计算的“算术运算符”,比较2个运算数大小的“比较运算符”,进行逻辑运算的“逻辑运算符”,对二进制位进行操作的“二进制运算符”,有对变量赋值的“赋值运算符”,还有一些特殊的运算符。

1.算术运算符(arithmetic operators)

表2-1是算术运算符的含义及其示例。需要注意的是,//表示整数除法,而/表示的是浮点除法,%用于求2个整数相除的余数。例如:

表2-1 算术运算符的含义及其示例

x=15
y=2
print('x + y=', x+y)
print('x - y=', x-y)
print('x * y=', x*y)
print('x / y=', x/y)
print('x // y=', x//y)
print('x ** y=', x**y)
print('x % y=', x%y)

输出:

x + y=17
x - y=13
x * y=30
x / y=7.5
x // y=7
x ** y=225
x % y=1

再如:

print(15.3/2.5)
print(15.3//2.5)     #转为整数除,相当于15//2
print(15.3%2.5)      #15.3除2.5的余数
print(15.3**2.5)     #15.3的2.5次方

输出:

6.12
6.0
0.3000000000000007
915.6480546203329

2.比较运算符(comparison operators)

表2-2是比较运算符及其含义和示例。

表2-2 比较运算符的含义及其示例

对两个量进行比较,产生的结果是一个表示“真”(True)或“假”(False)的bool(布尔)类型的值。例如:

x=15
y=2
print('x > y  is', x>y)
print('x < y  is', x<y)
print('x==y is', x==y)
print('x !=y is', x!=y)
print('x >=y is', x>=y)
print('x <=y is', x<=y)

输出:

x > y  is True
x < y  is False
x==y is False
x !=y is True
x >=y is True
x <=y is False

3.逻辑运算符(logical operators)

逻辑运算符and、or、not分别表示逻辑与、逻辑或、逻辑非运算。

在逻辑运算中,True、非0或非空对象就是真(True),而False、0或空对象就是假(False)。

当一个对象x是真(True、非0值或非空值)时,not x就是False,当x是假(False、0或空值)时,not x就是True(真)。例如:

print(not 0)
print(not [])
print(not False)
print(not 2)
print(not [3])
print(not True)

输出:

True
True
True
False
False
False

假设有2个对象x、y,当x是真时,x or y的结果就是x,当x是假时,x or y的结果就是y。

例如:

print(3 or 5)    #因为3是真,所以3 or 5的结果就是3
print(3 or 2)    #因为3是真,所以3 or 2的结果就是3
print(0 or 2)    #因为0是假,所以0 or 2的结果就是2
print(False or True)
print(False or [])
print({} or 2)   #因为{}是假,{} or 2的结果就是2

输出:

3
3
2
True
[]
2

假设有2个对象x、y,当x是真时,x and y的结果就是y,当x是假时,x and y的结果就是x。例如:

print(3 and 5)    #因为3是真,所以3 and 5的结果就是5
print(3 and 2)    #因为3是真,所以3 and 2的结果就是2
print(0 and 2)    #因为0是假,所以0 and 2的结果就是0
print(False and True)
print(False and [])
print({} and 2)   #因为{}是假,所以{} and 2的结果就是{}

输出:

5
2
0
False
False
{}

逻辑运算符and、or、 not的含义及其示例如表2-3所示。

表2-3 逻辑运算符的含义及其示例

这3个逻辑运算符具有不同的优先级,and优先于or, not优先于and、or。例如:

print(2 or 5 and 3)
print((2 or 5)and 3)#可用圆括号()改变运算符的计算次序

输出:

2
3

4.位运算符(bit operators)

任何量在计算机内存里都是用1串二进制位表示的。

假如有2个数,a=37和b=22是用1字节表示的,则其内存的二进制位如下所示:

a=0 0 1 0 0 1 0 1
b=0 0 0 1 0 1 1 0

位运算”:对运算数的二进制位进行相应的运算。其中,&(位与)、|(位或)、^(异或)是对2个运算数的对应二进制位进行运算,而~(取反)、<<(左移位)、>>(右移位)则是对1个运算数的二进制位进行运算。

二元位运算符的运算规则如表2-4所示。3个二元位运算符的运算规则如下。

表2-4 二元位运算符的运算规则

● &(位与)运算:只有p和q都是1时,p&q的结果才是1;如果有一个为0,则结果是0。

● |(位或)运算:只要p和q有一个是1时,p|q的结果就是1;如果p和q都为0,则结果是0。

● ^(异或)运算:当p和q不同(一个是0,另一个是1)时,p^q的结果是1,否则结果是0。

例如,对a、b的&、|、^运算是对它们的对应二进制位进行运算:

a&b =0 0 0 0 0 1 0 0
a |b=0 0 1 1 0 1 1 1
a^b =0 0 1 1 0 0 1 1

下面是对a、b的&、|、^运算的代码。

a=37
b=22
print('a=', '{:08b}'.format(a))
print('b=', '{:08b}'.format(b))
print('a&b=', '{:08b}'.format(a&b))
print('a|b=', '{:08b}'.format(a|b))
print('a^b=', '{:08b}'.format(a^b))

str的format()函数格式化输出a、b、a&b、a|b、a^b的二进制字符串。输出如下:

a= 00100101
b= 00010110
a&b=00000100
a|b=00110111
a^b=00110011

一元位运算符取反~、左移<<、右移>>的运算规则如下。

● ~(取反):将每个二进制取反(0变成1,1变成0)。例如,对x, ~x的结果相当于-x-1,如22的补是-23。

● <<(左移):各二进制位全部左移若干位,高位丢弃,低位补0。

● >>(右移):各二进制位全部左移若干位,无符号数,高位补0。

例如,对b的<<、~运算的结果如下:

b<<2=0 1 0 1 1 0 0 0
~b=1 1 1 0 1 0 0 1

下面代码输出了对b的<<、>>运算的二进制表示:

print('b=  ', '{:08b}'.format(b))
print('b<<2: ', '{:08b}'.format(b<<2))     #b的二进制左移2位,右边低位补充0
print('b>>2: ', '{:08b}'.format(b>>2))     #b的二进制右移2位,左边高位补充0
print('~b:   ', '{:08b}'.format(~b))        #~b就是-(b+1), b=22的补是-23
print(b)
print(b<<2)
print(b>>2)
print(~b)

输出如下:

b=  00010110
b<<2:  01011000
b>>2:  00000101
~b:   -0010111
22
88
5
-23

其中的取反运算~涉及1个数在计算机内部的二进制表示。数字在计算机中是以补码保存的,所以Python位运算是作用在补码上的。假如,用8位二进制表示,正整数1,其二进制的原码是00000001,而负整数-1,其二进制的原码是10000001,即左边的最高位1表示这是一个负数。除原码外,1个数在计算机内部还可以用反码和补码表示。正数的反码与其补码和原码是一样的,如1的反码和补码都是0000001,而负数的反码除左边最高位外,其他位都是原码的取反,如-1的反码是11111110,而补码就是在反码基础上加上1,即-1的补码是11111111。

b=22的原码、反码和补码都是00010110。对b的二进制取反的结果就是11101001,这个数实际上是-(b+1)的补码。因为-b的二进制原码是10010110,而-(b+1)的二进制原码是10010111,其补码就是11101001。但bin()和str的fromat()会将~b的补码表示转换成原码表示,因此,尽管~b运算产生的二进制是11101001,但显示的仍是其二进制原码10010111。

5.赋值运算符

赋值运算符=是给1个对象起1个名字,如简单的赋值运算符=的语句“x=3”,就是给对象3起了一个变量名x。例如:

x=2
x=x+3

在表达式“x=x+3”中,右边的变量x引用的是原先的对象,而左边的变量x引用的是新的结果对象。

简单赋值运算符可以和算术、位运算结合构成复合赋值运算符。例如:

x=2
x+=3

“x +=3”实际上是“x=x+3”的简写,即“将x+3的结果赋值给x”,也就是说,给x+3的结果对象起了一个名字x。变量x现在引用的是一个新的结果对象而不是原来的2,可以通过输出x的id来验证这一点:

x=2
y=x     # y和x都是对象2的名字
print(x)
print(id(x))
x**=3   #相当于x=x**3
print(x)
print(id(x))
print(y)
print(id(y))

输出:

2
1477476432
8
1477476624
2
1477476432

Python的赋值运算符如表2-5所示。

表2-5 赋值运算符

6.成员运算符(in、not in)

成员运算符in和not in用于判断一个值(对象)是否在一个容器对象,如list、str、tuple对象中,这2个运算符返回的结果是True或False。

alist=[2,5,7,8]
print(3 in alist)
print(5 in alist)
print(3 not in alist)
print(5 not in alist)

输出:

False
True
True
False

7.身份运算符:is、is not

身份运算符isis not用于判断2个变量(标识符)是不是引用的同一个对象。例如:

a=10
b=10
print(id(a))
print(id(b))
print(a is b)
print(a is not b)

输出:

1477476688
1477476688
True
False

再如:

a=1000
b=1000
print(id(a))
print(id(b))
print(a is b)
print(a is not b)

输出:

2417203138160
2417203138192
False
True

这是因为,Python解释器执行时会将小整数驻留在内存中,将小整数赋值给多个变量,它们实际引用的是同一个对象。而将整数赋值给不同变量,这些变量将引用临时创建的不同对象。

2.5.3 运算符的优先级

1.运算符的优先级

当一个表达式中有多个运算符时,这些运算符的计算是有先后次序的,即运算符是具有不同的优先级的。例如,算术运算符总是“先乘除,后加减”,同样级别的运算符,如+和-则按照“自左往后的次序”计算。例如:

3+5/2-4

先做除法“5/2”,然后做加法,即用“3”和“5/2”的结果相加,最后才做减法,即前面加法的结果和4相减。

再比如,同样是逻辑运算,not比and优先级高,而and比or优先级高。

实际上,无须记忆这些运算符的优先级,如果不清楚不同运算符的优先级,则可以简单地用圆括号,使其按照希望的意图进行计算。例如:

(3+5)/(2-4)

2.运算符的优先级表

表2-6是Python运算符的优先级表(从上到下优先级从高变低)。

表2-6 Python运算符的优先级表

总结

● 表达式是用运算符对运算数进行运算的式子,运算数包括值或变量,变量实际就是值对象的引用。

● 常见的运算符按照其功能,主要包括算术运算符、逻辑运算符、比较运算符、位运算符。还有一些其他的运算符,如比较运算符(in和not in)、身份运算符(is和is not)。

● 不同的运算符具有不同的优先级,优先级高的先运算。无须记忆运算符的优先级,因为可以用圆括号保证正确的运算顺序。