算术运算符
算术运算符,你一定不会陌生,因为这是小学1年级就开始学习的知识,最简单的莫过于加减乘除,编程语言里的算术运算符没有超出你小学所学。本文所用示例代码,均是在交互式解释器中运行的代码。
| 运算符 | 描述 | 实例 |
|---|---|---|
| + | 两个对象相加 | 5 + 4 结果为9 |
| - | 两个对象相减 | 5 - 4 结果为1 |
| * | 两个对象相乘 | 5 * 4 结果为20 |
| / | 两个数做除法 | 5 / 4 结果为1.25 |
| % | 取模,返回除法的余数 | 5 % 4 结果为1 |
| ** | 幂,返回x的y次幂 | 5**4, 5的4次方,结果为625 |
| // | 向下取整的除法 | 5//4 结果是1, -5//4结果是-2 |
1. +
前面举例子时用两个整数举例子说明+ 运算符的作用,+ 运算符不只是能用于数字间的运算,字符串,列表也可以用这个运算符进行运算
>>> "py" + 'thon''python'>>> [12, 1, 2] + [32, 22][12, 1, 2, 32, 22]
2. -
- 运算符用于两个数据相乘,除了可以作用于两个数字类型之间的运算,还有一种特别的用法
在上面的例子中,* 不在表示乘法,而是表示重复多少次,它可以作用于字符串,列表,元组>>> 'python'*3'pythonpythonpython'>>> [1, 2, 3]*3[1, 2, 3, 1, 2, 3, 1, 2, 3]>>> (1, 2, 3)*3(1, 2, 3, 1, 2, 3, 1, 2, 3)
4. /
/ 除法运算符,强调一点,不管能否整除,该运算符的计算结果都是float类型>>> 4/22.0>>> 5/22.5
5. %
% 运算符是一个很简单,但是作用非常强大的运算符,它返回除法结果中余数的部分
它可以用来判断一个数是否为另一个数的整数倍,判断奇偶就要依靠它,它的作用不仅限于此,后面的教程中你还会用到它>>> 5%21>>> 6%20
6. **
** 计算幂,没什么可讲的7. //
// 取整除法,你需要掌握两点
- 结果一定为整数
- 向下取整
5/4 = 1.25 ,1.25向下取整,比1.25小的最近的整数是1,因此5//4 = 1
-5/4 = -1.25, -1.25向下取整,比-1.25小的最近的整数是-2,因此-5//4 = -2
比较运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
| == | 比较对象是否相等 | 5 == 5 结果为True |
| != | 比较两个对象是否不相等 | 5 != 4 结果为True |
| > | 大于 | 5 > 4 结果为True |
| < | 小于 | 4 < 5 结果为True |
| >= | 大于等于 | 5 >= 5 结果为True |
| <= | 小于等于 | 4 <=5 结果为True |
比较运算符用于比较数据之间的关系,由比较运算符构成的表达式,其结果为bool类型
1. ==
比较两个对象是否相等,这个运算符可以比较所有的数据类型
>>> 1 == 1True>>> 1.0 == 1.0True>>> True == TrueTrue>>> '123' == '123'True>>> [1, 2, 3] == [1, 2, 3]True>>> (1, 2, 3) == (1, 2, 3)True>>> {1, 2, 3} == {1, 2, 3}True>>> {'a': 1} == {'a': 1}True
除了这些基础数据类型,自定义类创建的对象也可以用 == 进行比较
2. !=
这个运算符的作用与 == 刚好相反,判断运算符两侧的数据是否不相等
3. > 与 <
比较两个数据的大小关系
>>> 12 > 4True>>> 5 < 7True
这两个操作符除了可以比较数字类型数据,还可以用来比较两个字符串的大小
>>> 'abc' > 'bc'False>>> 'abc' < 'bc'True>>> 'bc' < 'a'False
比较两个字符串时,首先比较两个字符串的首字母,以首字母大小决定整个字符串的大小,如果首字母相同,则比较下一个字母,比较规则和首字母一样。以此规则逐个字母进行比较,直到分出大小
>>> 'abc' < 'abc5'True
上面的例子中,前3个字母没有分出大小,而其中一个字符串已经到末尾了,这种情况,长度较长的算大
4. >= 和 <=
比较规则可以参考> 和 < ,关于比较运算符这块,真没什么可讲的,因为这部分内容几乎和编程没有什么关系,纯粹是一种基础的人人都会的大小比较
赋值运算符
a = 345b = 5 > 4
上面两行代码都是赋值语句, 等号是赋值运算符,赋值运算符的右侧,是一个对象,也可以是一个表达式,等号左侧则必须是变量,赋值运算符将右侧的表达式的值赋值给左侧的变量。
1. 先计算赋值运算符右侧的表达式
a = 0a = a + 1
永远先计算等号右侧的表达式,以 a = a+1为例,先计算表达式a + 1的值,此时a = 0 , a + 1 = 0 + 1 = 1。 等号右侧表达式的值为1,将1赋值给变量a,最终a = 1
2. 与其他算术运算符结合
与其他算术运算符结合,产生新的语法,让代码看起来更加简洁,下面是加法赋值运算符的例子
a = 0a += 1 # 等价于 a = a + 1
这种算术运算符在前,等号在后的表示方式还6种,分别是
1. -= 减法赋值运算符2. *= 乘法赋值运算符3. /= 除法赋值运算符4. %= 取模赋值运算符5. **= 幂赋值运算符6. //= 取整除赋值运算符
3. 元组赋值
同时对两个或多个变量进行赋值,可以采用元组赋值
a , b = 1, 2a, b, c = 3, 4, 5
4. 多目标赋值
如果对两个或多个变量进行赋值时,他们的初始值都相同,那么,就没有必要使用元组赋值方式,而应该采用多目标赋值
a=b=c=1
用这种方式,a, b, c 的值都是1
但在使用这种方式时,有一个坑你需要注意
a = b = c = [1]print(id(a))print(id(b))print(id(c))
程序输出结果
441496692044149669204414966920
这3个变量的内存地址是相同的,而如果你采用单个变量赋值的基本形式,则不会相同
a = [1]b = [1]c = [1]print(id(a))print(id(b))print(id(c))
程序输出结果
437778343243777836884377784264
用这种方式,每一行赋值语句,都会在内存中创建一个列表再赋值给变量,因此他们的内存地址不同。
使用a = b = c = [1]这种多目标赋值方法,其过程是这样的,先创建列表[1],赋值给a, 然后执行b = a, c = a,因此在使用多目标赋值语法时,不要将可变对象赋值给多个变量,一面他们之间互相影响。
逻辑运算符
| 运算符 | 逻辑表达式 | 描述 | 实例 |
|---|---|---|---|
| and | x and y | x和y都为True时,结果为True,否则为False | True and True 结果为True, 有一个为False,表达式结果即为False |
| or | x or y | x和y只要有一个为True,则表达式结果为True | True or False 结果为True |
| not | not x | x 为Ture, not x 则为False, x为False, not x 结果为True | not (3 > 4 and 5 > 3) 结果为True |
and 是布尔与运算,表示并且的意思,并且想要成立,就要求并且两边的表达式都为True,有一个是Flase,表达式为False
or 是布尔或运算,表示或的意思,只有一个条件成立了,整个表达式的结果即为True
not 是布尔非运算,表示相反的意思,就是把True和False颠倒过来。
实际使用中,表达式看起来会很复杂,甚至会使用小括号,那么优先计算小括号里的表达式结果
True and (3 > 2 or 2 > 100) # 结果True(5 > 4 and 3%2 == 1) or (4 == '' and True) # 结果为True4 and 0 # 结果为False
- 不论多复杂的逻辑表达式,有小括号,先计算小括号里的结果
- 在逻辑表达式中,0,None, 空字符串,空列表,空字典,空集合等价于False, 其余的数据等价于True
位运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| & | 按位与运算符:参与运算的两个值,对应为都为1,则结果位为1,否则为0 | 1 & 2 = 0 |
| | | 按位或运算符:参与运算的两个值,对应位只要有一个为1,结果位则为1 | 1 | 2 = 3 |
| ^ | 按位异或运算符:参与计算的连个值,对应位不同,则结果位为1,对应位相同,则结果位为0 | 1 ^ 2 = 3 |
| ~ | 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1 | ~5 = 2 |
| << | 左移动运算符:运算数的各二进位全部左移若干位,高位丢弃,低位补0。 | 2 << 2= 8 |
| >> | 右移动运算符:参与运算的值的各二进位全部右移若干位 | 8 >> 1 = 4 |
位运算是在2进制的层面上对数据进行计算,下面逐个解释上表中的例子,在32位机器上,c语言中的int类型数据占4个字节,也就是32个比特位,3的二进制表示形式为
00000000 00000000 00000000 00000011
在python语言中,一个int类型占多少字节不是固定的,因此下面的讲解中,我在描述一个数值的二进制时,低8位。
& 按位与运算符
1 的二进制表示形式是 00000001
2 的二进制表示形式是 00000010
对应为进行与运算,只有都为1时,结果位才会为1,因此最终结果为为 0000000,转成10进制是0
下面再举一个例子,你自己可以同时进行运算
1 & 3 = 100000001 1的二进制00000011 3的二进制00000001 1的二进制
| 按位或运算符
1 的二进制表示形式是 00000001
2 的二进制表示形式是 00000010
对应为只要有一个是1,那么结果位就是1,对应位都是0,则结果位是0,最终结果是00000011 ,转换成10进制是3
下面再举一个例子,你自己可以实验一下
4 | 8 = 1200000100 4的二进制00001000 8的二进制00001100 12的二进制
^ 按位异或运算符
1 的二进制表示形式是 00000001
2 的二进制表示形式是 00000010
对应位不同,则结果位是1,对应位相同,则结果位是0,计算结果为00000011,转换成10进制为3
下面再举一个例子,你自己可以实验一下
4 ^ 5 = 100000100 4的二进制00000101 5的二进制00000001 1的二进制
~ 按位取反运算符
按位取反时,二进制的0变成1,1变成0
理解按位取反运算,先要理解几个基本概念
- 原码
- 反码
- 补码
原码: 一个整数,按照绝对值大小转换成的二进制数,称为原码,2 的原码是10, -3的原码是11
反码: 将二进制数按位取反,所得的新二进制数称为原二进制数的反码
补码:反码加1称为补码
计算~5的结果:
- 5 的2进制表示是 0000 0000 0000 0000 0000 0000 0000 0101
- 按位取反后是1111 1111 1111 1111 1111 1111 1111 1010,结果是-6,最高位是1表明它是一个负数
- 负数在计算机中使用补码来存储,负数的补码是其反码加1并在前面加一个负号,-6的补码是0000 0000 0000 0000 0000 0000 0000 0101,加1后并在前面加一个负号的结果是-0000 0000 0000 0000 0000 0000 0000 0110
按位取反计算逻辑可以总结为: ~n = -(n+1)
print(bin(~5))
程序输出结果
-0b110
<< 左移动运算符
2 << 2
2 的二进制表示形式 00000010
向左移动2位后变成 00001000
左移动,相当于乘2,左移动多少,就乘多少次2
3 << 4 等价于 3 (2**4) = 316 = 48
>> 右移动运算符
8 >> 1
8的二进制表示形式 00001000
向右移动1, 00000100 ,转成10进制是4
右移动,相当于除2,右移动多少,就除多少次2
17 >> 2 等价于17除 2**2 ,等价于17/4 = 4
00010001 17的二进制向右移动两位00000100 转成10进制是4
成员运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| in | 如果在指定的序列中找到值返回 True,否则返回 False。 | 3 in [1, 2, 3] 表达式结果为True |
| not in | 如果在指定的序列中没有找到值返回 True,否则返回 False。 | 3 not in [1, 2, 3] 表达式结果为False |
这是两个比较简单的运算符,in可以作用于字符串,列表,元组,字典,集合
>>> 'a' in 'abc'True>>> 1 in [1, 2, 3]True>>> 2 in (1, 2, 3)True>>> 3 in {1, 2, 3}True>>> 'key' in {'key': 'value'}True
如果你掌握了in 这个运算符,那么not in 也就顺带手的理解了,not in 就是对in 的一个否定判断。
身份运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| is | is 是判断两个标识符是不是引用自一个对象 | 本质上是判断两个对象的内存地址是否相同 |
| is not | is not 是判断两个标识符是不是引用自不同对象 | 与is功能相反,本质上仍然是对两个对象的内存地址是否相等进行判断 |
先来几个示例,感受一下它的功能
a = 1b = 1print(a is b)
程序输出结果
True
is 与 == 的区别
a = [1, 2, 3] # 创建一个新的列表b = [1, 2, 3] # 创建一个新的列表print(a == b)print(a is b)print(id(a), id(b))
程序输出结果
TrueFalse4367682696 4367682952
== 比较运算符,比较的是两个对象的值是否相等,从字面上看,这两个列表的值是完全相等的
is 是身份运算符,它比较的是两个对象的内存地址是否相同,如果内存地址相同,那么他们就是同一个对象。
上面的示例代码中,虽然列表的值相同,但他们是在两个不同的赋值语句中被创建的,因此他们的内存地址不同
同时对两个变量赋值1,为什么这两个1的内存地址相同
a = 1b = 1print(a is b)
程序输出结果
True
为什么这两个1的内存地址会相同呢?这里和python的内存管理有关,python设计者认为在[-5, 257)这个范围内的整数,是经常被使用的对象,因此,没有必要经常性的创建和释放他们,于是python建立了一个内存池,存储了这个范围内的整数,当你使用这个范围内的整数时,其实都是从这个内存池中取数,并没有重新创建
>>> a = 256>>> b = 256>>> a is bTrue>>> a = 257>>> b = 257>>> a is bFalse
如果超出这个范围,尽管值相同,但是已经超出了内存池存储数据范围,因此分别在内存中创建了两个257,他们的内存地址不同
运算符优先级
下表从高到低列出了所有运算符
| 运算符 | 描述 |
|---|---|
| ** | 指数 (最高优先级) |
| ~ + - | 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@) |
| * / % // | 乘,除,取模和取整除 |
| + - | 加法减法 |
| >> << | 右移,左移运算符 |
| & | 位 ‘AND’ |
| ^ | | 位运算符 |
| <= < > >= | 比较运算符 |
| <> == != | 等于运算符 |
| = %= /= //= -= += = *= | 赋值运算符 |
| is is not | 身份运算符 |
| in not in | 成员运算符 |
| not or and | 逻辑运算符 |
优先级运算示例
print(5 + 5 >> 2) # 先计算5 + 5=10 ,然后计算10 >> 2, 结果是2print(1 + 4 & 1) # 先计算1 + 4=5, 然后计算5 & 1, 结果是1print(3**2*4) # 先计算3**2 = 9,然后计算9*4, 结果是36a = 3a**= 2*2print(a) # 先计算2*2 = 4,然后计算3**4, 结果是
表达式
本篇文章共4个章节:
- 初学者是否有必要学习编程专业词汇
- 表达式的概念
- 表达式的应用
- 总结
1. 初学者是否有必要学习编程专业词汇
表达式是一个很专业的词汇,但凡是搞编程的,恐怕没有不理解的,即便说不出准确的定义,也能大概理解其中含义。对于初学者而言,有必要和这些专业词汇较劲么,我认为有必要。
有些教程或者文章,喜欢用大白话讲解,固然可以降低初学者学习门槛,可是,编程本身是一项专业性很强的技术,所涉及到的概念,如果不能准确理解,正确使用,一开始影响倒也不大,因为你大多数时间都是在照猫画虎。但肯定会影响到你后续的学习,这是因为随着学习的深入,你遇到的问题变得复杂,复杂到不使用专业词汇就无法精准的定义和解释问题,大白话文章无法让你更上一层楼,你只能永远肤浅的入门,然后一辈子在一楼打转。2. 表达式的概念
先来看百度百科里的定义:
表达式,是由数字、算符、数字分组符号(括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合
这个定义有点长,不好理解,咱们做个优化,将其总结为一个更短更容易理解的定义:表达式是可以被求值的代码
有了这个定义,下面罗列一些表达式
每一行都是一个表达式,他们有一个共同点,可以被求值,如果用print输出这些表达式,总能输出一个数值。4 > 53 == 3.0'abc' == 'abc' and True5(4 + 5)5 >> 17 > 4 or (1 == 1 and 6 > 7)
3. 表达式的应用
表达式的应用无处不在,如果没有表达式,也就没有编程这个事情了3.1 赋值语句
这应该是表达式使用最多的场景了
我们甚至可以粗暴的认为,所有赋值语句中,等号的右边都是表达式,在执行赋值语句时,先要计算等号右侧的表达式,将表达式的结果赋值给等号左侧的变量
a 最终的值为Truea = 3 > 4 or True
3.2 if 语句
紧跟在if 后面的部分(表达式1)就是表达式,当这个表达式的结果为True时,执行语句块1,否则判断紧跟在elif后面表达式2,如果表达式2的结果为True,则执行语句块2,如果前面的两个表达式的结果都是False,则最终执行语句块3。if 表达式1:语句块1elif 表达式2:语句块2else:语句块3
一些文章在讲述表达式为True时,会用表达式成立这样的说法,其实是一个意思。
下面是程序流程图
不论if语句中有多少个逻辑分支,永远只会进入其中一个,即便其他的表达式也是成立的,因为在执行if语句时,遵守短路原则,前面的判断语句如果成立了,后面的判断语句就不会被执行,相当于打麻将时的截胡。3.3 while 循环
如果表达式A成立,则执行语句块A,语句块A执行结束后,会再次判断表达式A是否成立,成立继续执行语句块A,不成立,循环结束,下图为循环流程示意图while 表达式A:语句块A
3.4 函数返回值
上述代码中的a + b就是一个表达式,a + b的结果作为函数的返回值返回def add(a, b):return a + b
4.总结
或许你觉得表达式太简单了,但编程就是由这些看似十分简单的概念构成的,不要认为简单就粗心大意,真的让你写程序时,恐怕你就不知道表达式该咋写了。
