《手把手陪您学Python》13——运算

在上一篇《手把手陪您学Python》12——数字中,我们学习了数字的类型、运算、函数等内容。在这一篇中,我们将在数字运算的基础上,继续扩展Python的运算类型。这其中可能有一些我们平时接触不到的运算方式,但总体难度不大。

首先,我们先定义两个概念,一个叫做操作数,一个叫做运算符。以最简单的1+2来说,1和2就是操作数,+就是运算符。

其次,我们再给运算定义一个分类方式。根据操作数数量的不同,可以将运算分成一元运算、二元运算和三元运算。比如-2的操作数只有1个2,就是一元运算。1+2的操作数是1和2,就是二元运算。因为三元运算会涉及到我们后面将要介绍的判断函数,暂且不提。至于四元或者更多元的运算,可能有,但就没有人这么说了。

最后,我们简单了解一下一元运算。一元运算因为只有一个操作数,所以相对简单。相应地,一元运算操作符也就是那么几个。一般我们会用到的一元运算操作符就是正号(+)和负号(-)。

做了上面一个小小的铺垫后,我们就开始今天的主题——Python的运算,或者更确切地说是Python的二元运算。

我们在平时接触最多的就是二元运算,包括我们平时所说的算数运算、比较、包含、逻辑运算等等,都属于二元运算。

只是在Python中,又使用计算机语言对上面提到的二元运算和我们平时可能会接触到,但并不认为也是一种运算的运算进行了规范,并将其分成了如下7类:

算术运算

赋值运算

比较运算

逻辑运算

成员运算

身份运算

位运算

下面,我们就按照这7种类别,对Python的二元运算进行逐一的讲解。

1、算数运算

关于算数运算,在上一篇《手把手陪您学Python》12——数字中已经做了详细的介绍,在这一篇中就不再赘述了,请大家移步进行了解。

2、赋值运算

赋值运算是在算数运算的基础上衍生而来的,因为赋值运算实际上是执行了两个过程——先做算数运算再赋值,而且这个赋值是给位于赋值运算符左边的操作数的。举个例子:

c = a + b是将a和b的运算结果赋值给c,这只是普通的算数运算然后再赋值。

同理,a = a + b也只是普通的算数运算然后再赋值,只不过是将运算结果赋值给了其中一个操作数。但当a = a + b写成等效的a += b时就变成了赋值运算了,先执行了a + b,再将a + b的值赋值给位于赋值运算符左边的操作数a。

所有的算数运算都可以通过在算数运算符后面加一个=号,变成赋值运算。

In [1]: a = 11
        b = 3
​
In [2]: a += b
        a
Out[2]: 14
​
In [3]: a = 11
        a -= b
        a
Out[3]: 8
​
In [4]: a = 11
        a *= b
        a
Out[4]: 33
​
In [5]: a = 11
        a /= b
        a
Out[5]: 3.6666666666666665
​
In [6]: a = 11
        a **= b   # a的b次幂
        a
Out[6]: 1331

In [7]: a = 11
        a %= b   # 11除3等于3,余数为2
        a
Out[7]: 2
​
In [8]: a = 11
        a //= b   # 11除3等于3余2,向下取整数部分为3
        a
Out[8]: 3

在上面的实例中,因为对a进行了赋值运算,所以a的值会变化,所以在执行下一个实例前,需要再将a赋值成11。

3、比较运算

比较运算就是我们在数学中常用的大于(>)、小于(<)、等于(==)、不等于(!=),以及大于等于(>=)、小于等于(<=)。

因为在计算机语言中,“=”已经被用作赋值符号了,所以,所有的等于号都使用“==”来代表。同样还有与我们平时使用的数学符号不同的包括“!=”、“>=”以及“<=”,大家在使用时注意一下就好。

比较运算的结果使用布尔值来表示,就是我们之前提过的True和False(大小写为固定表达)。除了比较运算,布尔值还会应用到我们一会儿将要讲到的逻辑运算、成员运算和身份运算中。

In [9]: a = 2
        b = 3
​
In [10]: a > b
Out[10]: False
​
In [11]: a < b
Out[11]: True
​
In [12]: a == b
Out[12]: False
​
In [13]: a != b
Out[13]: True
​
In [14]: a >= b
Out[14]: False
​
In [15]: a <= b
Out[15]: True

4、逻辑运算

在讲逻辑运算前,我们还需要把布尔值再深入地讲解一下。

我们之前说过,布尔值有两个,分别是代表真的True、代表假的False。除了True和False外,真和假还可以用1和0来表示,或者说1和0分别是True和False的数值形式。而因为True和False有了数值形式,所以就可以进行算数运算了。

In [16]: True + True
Out[16]: 2
​
In [17]: True - False
Out[17]: 1
​
In [18]: True * 5
Out[18]: 5
​
In [19]: True * False
Out[19]: 0

最后补充一句。在接下来要讲的逻辑运算中,代表“真”的范围更大,所有不为0的数都代表“逻辑真”,只有0代表“逻辑假”。

逻辑运算包括三种,分别是and、or、not。

and代表“与”。对于a and b的形式来说,如果a为True或者“逻辑真”(即所有非0数字),a and b的值就等于b。如果a为False或者“逻辑假”(即0),a and b的值就等于False或0(与a的值是False还是0保持一致)。

In [20]: a = True   # a为True,结果等于b
         b = 5
         a and b
Out[20]: 5
​
In [21]: a = -8.5   # a为非0数字,相当于True,结果等于b
         b = 5
         a and b
Out[21]: 5
​
In [22]: a = False   # a为Fasle,结果为False
         b = 5
         a and b
Out[22]: False
​
In [23]: a = 0   # a为0,相当于False,结果为0
         b = 5
         a and b
Out[23]: 0

or代表“或”。对于a or b的形式来说,如果a为True或者“逻辑真”(即所有非0数字),a or b的值就等于a。如果a为False或者“逻辑假”(即0),a or b的值就等于b。

In [24]: a = True   # a为True,结果等于a
         b = 5
         a or b
Out[24]: True
​
In [25]: a = -8.5   # a为非0数字,相当于True,结果等于a
         b = 5
         a or b
Out[25]: -8.5
​
In [26]: a = False   # a为False,结果等于b
         b = 5
         a or b
Out[26]: 5
​
In [27]: a = 0   # a为0,相当于False,结果等于b
         b = 5
         a or b
Out[27]: 5

not代表“非”。对于not a的形式来说,如果a为True或者“逻辑真”(即所有非0数字),not a的值就等于False(没有等于0 的情况)。如果a为False或者“逻辑假”(即0),not a的值就等于True(没有等于非0数字的情况)。

In [28]: a = True   # a为True,结果等于False
         not a
Out[28]: False
​
In [29]: a = -8.5   # a为非0数字,相当于True,结果等于False
         not a
Out[29]: False
​
In [30]: a = False   # a为False,结果等于True
         not a
Out[30]: True
​
In [31]: a = 0   # a为0,相当于False,结果等于True
         not a
Out[31]: True

5、成员运算

成员运算有包括两种,分别是in和not in。成员运算可以直接按照字面意义理解,就是判断是不是成员的运算。

对于in,如果在指定序列中能够找到值,就返回True,否则返回False。对于not in,如果在指定序列中不能够找到值,返回True,否则就返回False。

In [32]: a = 2
         b = 0
         lst = [1, 2, 3, 4, 5]
​
In [33]: a in lst
Out[33]: True
​
In [34]: b in lst
Out[34]: False
​
In [35]: a not in lst
Out[35]: False
​
In [36]: b not in lst
Out[36]: True

6、身份运算

身份运算是用于比较两个对象是否指向同一个内存地址的, 身份运算包括两种:分别是is和not is。

对于is,如果两个变量的内存地址相同,就返回True,否则返回False。对于not is,如果两个变量的内存地址不同,返回True,否则就返回False。

要理解身份运算,需要首先了解一下Python的存储机制。

平时我们所说的变量,比如a = 1,我们能看到的是变量的名称(name)a,以及变量的值(value)1,其实还有另外一个属性是我们看不到的,就是变量存储的内存地址(id),存储地址可以使用id()函数来获取。

之前我们学习比较运算中的==,其实是对两个变量的值(value)是否相等进行判断的。而身份运算是对两个变量的内存地址(id)是否相等进行判断的。

所以,一般情况下,虽然我们看上去两个变量的值(value)是相同的,但是他们的内存地址(id)不一定相同。

In [37]: a = 'Hello World!'
         b = 'Hello World!'
         print("比较结果:a == b:{};a is b:{}。".format(a == b, a is b))   # ab都是相同的字符串,值相同,但是内存地址不同
Out[37]: 比较结果:a == b:True;a is b:False。

那么在什么情况下,变量的值相同,内存地址也相同呢?因为无论我们是否使用得到,Python都预先缓存了-5(含)到257(不含)之间的所有整数,所以,只有这262个整数,只要值相同,内存地址就相同。(这里可以理解一下,Python中的区间都是左闭右开的,所以不会说-5到256之间。)

In [38]: a = 5
         b = 5
         print("比较结果:a == b:{};a is b:{}。".format(a == b, a is b))   # ab在-5~257的左闭右开区间内,值相同,内存地址也相同
Out[38]: 比较结果:a == b:True;a is b:True。
​
In [39]: a = 257
         b = 257
         print("比较结果:a == b:{};a is b:{}。".format(a == b, a is b))   # ab不在-5~257的左闭右开区间内,值相同,但内存地址不同
Out[39]: 比较结果:a == b:True;a is b:False。
​
In [40]: a = -6
         b = -6
         print("比较结果:a != b:{};a is  not b:{}。".format(a != b, a is not b))   # ab不在-5~256的全闭区间内,值相同,但内存地址不同
Out[40]: 比较结果:a != b:False;a is  not b:True。

再举一个需要注意的例子。

当我们在程序运行或者调试的过程中,想复制一个变量,很容易地就会想到使用b = a进行复制。当我们修改b的值时,就不会影响a的值了。但世界有时并不像我们想象的那么简单,虽然我们用b复制了a,但由于a和b指向的是同一个存储单元,当我们修改b的值时,a的值也同时被修改了,并不会达到我们之前设想的目的。

In [41]: a = [0, 1, 2]   # a为一个列表
         b = a   # 因为不想改变a的值,所以使用b复制a的值进行修改
         print("a的内存地址是:{},b的内存地址是:{},身份运算b is a的结果为:{}。".format(id(a), id(b), b is a))
Out[41]: a的内存地址是:2269977123784,b的内存地址是:2269977123784,身份运算b is a的结果为:True。
​
In [42]: b.append(3)   # 给b增加一个元素3,append()是给列表增加元素的函数,后面会讲
         print("因为内存地址相同,所以b的值修改为:{}时,a的值也同样被修改为:{}。".format(a, b))
Out[42]: 因为内存地址相同,所以b的值修改为:[0, 1, 2, 3]时,a的值也同样被修改为:[0, 1, 2, 3]。

所以,在以后的学习中,大家要特别注意这一点。至于如何复制才能够像我们想象的一样,不同时修改原来变量的值,我们会在后面需要的时候再介绍。

7、位运算

位运算是针对二进制数进行的运算。不但运算规则有点烧脑,最主要的是我们用不上。所以,这里仅把几种位运算列出来供大家参考,在举两个例子让大家体验一下。

运算符

描述

实例

&

按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0

(a & b) 输出结果 12 ,二进制解释:0000 1100

|

按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。

(a | b) 输出结果 61 ,二进制解释:0011 1101

^

按位异或运算符:当两对应的二进位相异时,结果为1

(a ^ b) 输出结果 49 ,二进制解释:0011 0001

~

按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1。~x类似于 -x-1

(~a ) 输出结果 -61 ,二进制解释:1100 0011, 在一个有符号二进制数的补码形式。

<<

左移动运算符:运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。

a << 2 输出结果 240 ,二进制解释:1111 0000

>>

右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数

a >> 2 输出结果 15 ,二进制解释:0000 1111

上表的实例中,a的值为0011 1100,b的值为0000 1101。

a & b的结果是如果计算出来的呢?分解一下来说,就是a和b对应位置的数字做上面讲的逻辑运算“与”,其中,0代表False,1代表True。01组合和10组合都得到0,只有11组合得到1。下面的图片会看得更清楚:

 

再举一个例子,a >> 2是将a各位上的数字向右移动两位,尾部的数字相应移动到前面。

其它位运算的运算过程就留给大家去探索啦,如果不好理解,就像上面的例子一样,逐个数字按照规则进行计算即可。

以上就是Python中全部的运算类型,最后我们再了解一下这些运算的优先级。算数运算的优先级和我们数学中的一样,只要记住几个特殊的运算类型的优先级就可以了。相同优先级内的运算按照在公式中出现的从左到右的顺序计算,括号内的先计算,这些规则也都一样。

运算符

描述

**

指数 (最高优先级)

~ + -

按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@)

* / % //

乘,除,取模和取整除

+ -

加法减法

>> <<

右移,左移运算符

&

位 'AND'

^ |

位运算符

<= < > >=

比较运算符

<> == !=

等于运算符

= %= /= //= -= += *= **=

赋值运算符

is is not

身份运算符

in not in

成员运算符

not and or

逻辑运算符

至此,Python的运算也讲解完了。在后面的章节中,我们将突破传统教程中字符串、列表、字典、元组、集合的顺序,将控制流语句的介绍放到前面来,再结合之前讲的字符串、数字和运算的内容,我们就可以开编写我们自己的小程序了,敬请关注。

 

 


感谢阅读本文!如有任何问题,欢迎留言,一起交流讨论^_^

欢迎扫描下方二维码,关注“亦说Python”公众号,阅读《手把手陪您学Python》系列文章的其他篇目,或点击下方链接直达。

《手把手陪您学Python》1——为什么要学Python?

《手把手陪您学Python》2——Python的安装

《手把手陪您学Python》3——PyCharm的安装和配置

《手把手陪您学Python》4——Hello World!

《手把手陪您学Python》5——Jupyter Notebook

《手把手陪您学Python》6——字符串的标识

《手把手陪您学Python》7——字符串的索引

《手把手陪您学Python》8——字符串的切片

《手把手陪您学Python》9——字符串的运算

《手把手陪您学Python》10——字符串的函数

《手把手陪您学Python》11——字符串的格式化输出

《手把手陪您学Python》12——数字

For Fans:关注“亦说Python”公众号,回复“手13”,即可免费下载本篇文章所用示例语句。

亦说Python——Python爱好者的学习分享园地

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值