算术运算符

算术运算符,你一定不会陌生,因为这是小学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. +

前面举例子时用两个整数举例子说明+ 运算符的作用,+ 运算符不只是能用于数字间的运算,字符串,列表也可以用这个运算符进行运算

  1. >>> "py" + 'thon'
  2. 'python'
  3. >>> [12, 1, 2] + [32, 22]
  4. [12, 1, 2, 32, 22]

2. -

  • 运算符只能用于数字之间的计算,int和float

    3. *

  • 运算符用于两个数据相乘,除了可以作用于两个数字类型之间的运算,还有一种特别的用法
    1. >>> 'python'*3
    2. 'pythonpythonpython'
    3. >>> [1, 2, 3]*3
    4. [1, 2, 3, 1, 2, 3, 1, 2, 3]
    5. >>> (1, 2, 3)*3
    6. (1, 2, 3, 1, 2, 3, 1, 2, 3)
    在上面的例子中,* 不在表示乘法,而是表示重复多少次,它可以作用于字符串,列表,元组

    4. /

    / 除法运算符,强调一点,不管能否整除,该运算符的计算结果都是float类型
    1. >>> 4/2
    2. 2.0
    3. >>> 5/2
    4. 2.5

    5. %

    % 运算符是一个很简单,但是作用非常强大的运算符,它返回除法结果中余数的部分
    1. >>> 5%2
    2. 1
    3. >>> 6%2
    4. 0
    它可以用来判断一个数是否为另一个数的整数倍,判断奇偶就要依靠它,它的作用不仅限于此,后面的教程中你还会用到它

    6. **

    ** 计算幂,没什么可讲的

    7. //

    // 取整除法,你需要掌握两点
  1. 结果一定为整数
  2. 向下取整

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. >>> 1 == 1
  2. True
  3. >>> 1.0 == 1.0
  4. True
  5. >>> True == True
  6. True
  7. >>> '123' == '123'
  8. True
  9. >>> [1, 2, 3] == [1, 2, 3]
  10. True
  11. >>> (1, 2, 3) == (1, 2, 3)
  12. True
  13. >>> {1, 2, 3} == {1, 2, 3}
  14. True
  15. >>> {'a': 1} == {'a': 1}
  16. True

除了这些基础数据类型,自定义类创建的对象也可以用 == 进行比较

2. !=

这个运算符的作用与 == 刚好相反,判断运算符两侧的数据是否不相等

3. > 与 <

比较两个数据的大小关系

  1. >>> 12 > 4
  2. True
  3. >>> 5 < 7
  4. True

这两个操作符除了可以比较数字类型数据,还可以用来比较两个字符串的大小

  1. >>> 'abc' > 'bc'
  2. False
  3. >>> 'abc' < 'bc'
  4. True
  5. >>> 'bc' < 'a'
  6. False

比较两个字符串时,首先比较两个字符串的首字母,以首字母大小决定整个字符串的大小,如果首字母相同,则比较下一个字母,比较规则和首字母一样。以此规则逐个字母进行比较,直到分出大小

  1. >>> 'abc' < 'abc5'
  2. True

上面的例子中,前3个字母没有分出大小,而其中一个字符串已经到末尾了,这种情况,长度较长的算大

4. >= 和 <=

比较规则可以参考> 和 < ,关于比较运算符这块,真没什么可讲的,因为这部分内容几乎和编程没有什么关系,纯粹是一种基础的人人都会的大小比较

赋值运算符

  1. a = 345
  2. b = 5 > 4

上面两行代码都是赋值语句, 等号是赋值运算符,赋值运算符的右侧,是一个对象,也可以是一个表达式,等号左侧则必须是变量,赋值运算符将右侧的表达式的值赋值给左侧的变量。

1. 先计算赋值运算符右侧的表达式

  1. a = 0
  2. a = a + 1

永远先计算等号右侧的表达式,以 a = a+1为例,先计算表达式a + 1的值,此时a = 0 , a + 1 = 0 + 1 = 1。 等号右侧表达式的值为1,将1赋值给变量a,最终a = 1

2. 与其他算术运算符结合

与其他算术运算符结合,产生新的语法,让代码看起来更加简洁,下面是加法赋值运算符的例子

  1. a = 0
  2. a += 1 # 等价于 a = a + 1

这种算术运算符在前,等号在后的表示方式还6种,分别是

  1. 1. -= 减法赋值运算符
  2. 2. *= 乘法赋值运算符
  3. 3. /= 除法赋值运算符
  4. 4. %= 取模赋值运算符
  5. 5. **= 幂赋值运算符
  6. 6. //= 取整除赋值运算符

3. 元组赋值

同时对两个或多个变量进行赋值,可以采用元组赋值

  1. a , b = 1, 2
  2. a, b, c = 3, 4, 5

这种赋值方式,可以减少代码函数,让代码更加简洁

4. 多目标赋值

如果对两个或多个变量进行赋值时,他们的初始值都相同,那么,就没有必要使用元组赋值方式,而应该采用多目标赋值

  1. a=b=c=1

用这种方式,a, b, c 的值都是1
但在使用这种方式时,有一个坑你需要注意

  1. a = b = c = [1]
  2. print(id(a))
  3. print(id(b))
  4. print(id(c))

程序输出结果

  1. 4414966920
  2. 4414966920
  3. 4414966920

这3个变量的内存地址是相同的,而如果你采用单个变量赋值的基本形式,则不会相同

  1. a = [1]
  2. b = [1]
  3. c = [1]
  4. print(id(a))
  5. print(id(b))
  6. print(id(c))

程序输出结果

  1. 4377783432
  2. 4377783688
  3. 4377784264

用这种方式,每一行赋值语句,都会在内存中创建一个列表再赋值给变量,因此他们的内存地址不同。
使用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颠倒过来。
实际使用中,表达式看起来会很复杂,甚至会使用小括号,那么优先计算小括号里的表达式结果

  1. True and (3 > 2 or 2 > 100) # 结果True
  2. (5 > 4 and 3%2 == 1) or (4 == '' and True) # 结果为True
  3. 4 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的二进制表示形式为

  1. 00000000 00000000 00000000 00000011

在python语言中,一个int类型占多少字节不是固定的,因此下面的讲解中,我在描述一个数值的二进制时,低8位。

& 按位与运算符

1 的二进制表示形式是 00000001
2 的二进制表示形式是 00000010
对应为进行与运算,只有都为1时,结果位才会为1,因此最终结果为为 0000000,转成10进制是0
下面再举一个例子,你自己可以同时进行运算

  1. 1 & 3 = 1
  2. 00000001 1的二进制
  3. 00000011 3的二进制
  4. 00000001 1的二进制

| 按位或运算符

1 的二进制表示形式是 00000001
2 的二进制表示形式是 00000010
对应为只要有一个是1,那么结果位就是1,对应位都是0,则结果位是0,最终结果是00000011 ,转换成10进制是3
下面再举一个例子,你自己可以实验一下

  1. 4 | 8 = 12
  2. 00000100 4的二进制
  3. 00001000 8的二进制
  4. 00001100 12的二进制

^ 按位异或运算符

1 的二进制表示形式是 00000001
2 的二进制表示形式是 00000010
对应位不同,则结果位是1,对应位相同,则结果位是0,计算结果为00000011,转换成10进制为3
下面再举一个例子,你自己可以实验一下

  1. 4 ^ 5 = 1
  2. 00000100 4的二进制
  3. 00000101 5的二进制
  4. 00000001 1的二进制

~ 按位取反运算符

按位取反时,二进制的0变成1,1变成0
理解按位取反运算,先要理解几个基本概念

  1. 原码
  2. 反码
  3. 补码

原码: 一个整数,按照绝对值大小转换成的二进制数,称为原码,2 的原码是10, -3的原码是11
反码: 将二进制数按位取反,所得的新二进制数称为原二进制数的反码
补码:反码加1称为补码
计算~5的结果:

  1. 5 的2进制表示是 0000 0000 0000 0000 0000 0000 0000 0101
  2. 按位取反后是1111 1111 1111 1111 1111 1111 1111 1010,结果是-6,最高位是1表明它是一个负数
  3. 负数在计算机中使用补码来存储,负数的补码是其反码加1并在前面加一个负号,-6的补码是0000 0000 0000 0000 0000 0000 0000 0101,加1后并在前面加一个负号的结果是-0000 0000 0000 0000 0000 0000 0000 0110

按位取反计算逻辑可以总结为: ~n = -(n+1)

  1. print(bin(~5))

程序输出结果

  1. -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

  1. 00010001 17的二进制
  2. 向右移动两位
  3. 00000100 转成10进制是4

成员运算符

运算符 描述 实例
in 如果在指定的序列中找到值返回 True,否则返回 False。 3 in [1, 2, 3] 表达式结果为True
not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 3 not in [1, 2, 3] 表达式结果为False

这是两个比较简单的运算符,in可以作用于字符串,列表,元组,字典,集合

  1. >>> 'a' in 'abc'
  2. True
  3. >>> 1 in [1, 2, 3]
  4. True
  5. >>> 2 in (1, 2, 3)
  6. True
  7. >>> 3 in {1, 2, 3}
  8. True
  9. >>> 'key' in {'key': 'value'}
  10. True

如果你掌握了in 这个运算符,那么not in 也就顺带手的理解了,not in 就是对in 的一个否定判断。

身份运算符

运算符 描述 实例
is is 是判断两个标识符是不是引用自一个对象 本质上是判断两个对象的内存地址是否相同
is not is not 是判断两个标识符是不是引用自不同对象 与is功能相反,本质上仍然是对两个对象的内存地址是否相等进行判断

先来几个示例,感受一下它的功能

  1. a = 1
  2. b = 1
  3. print(a is b)

程序输出结果

  1. True

is 与 == 的区别

  1. a = [1, 2, 3] # 创建一个新的列表
  2. b = [1, 2, 3] # 创建一个新的列表
  3. print(a == b)
  4. print(a is b)
  5. print(id(a), id(b))

程序输出结果

  1. True
  2. False
  3. 4367682696 4367682952

== 比较运算符,比较的是两个对象的值是否相等,从字面上看,这两个列表的值是完全相等的
is 是身份运算符,它比较的是两个对象的内存地址是否相同,如果内存地址相同,那么他们就是同一个对象。
上面的示例代码中,虽然列表的值相同,但他们是在两个不同的赋值语句中被创建的,因此他们的内存地址不同

同时对两个变量赋值1,为什么这两个1的内存地址相同

  1. a = 1
  2. b = 1
  3. print(a is b)

程序输出结果

  1. True

为什么这两个1的内存地址会相同呢?这里和python的内存管理有关,python设计者认为在[-5, 257)这个范围内的整数,是经常被使用的对象,因此,没有必要经常性的创建和释放他们,于是python建立了一个内存池,存储了这个范围内的整数,当你使用这个范围内的整数时,其实都是从这个内存池中取数,并没有重新创建

  1. >>> a = 256
  2. >>> b = 256
  3. >>> a is b
  4. True
  5. >>> a = 257
  6. >>> b = 257
  7. >>> a is b
  8. False

如果超出这个范围,尽管值相同,但是已经超出了内存池存储数据范围,因此分别在内存中创建了两个257,他们的内存地址不同

运算符优先级

下表从高到低列出了所有运算符

运算符 描述
** 指数 (最高优先级)
~ + - 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@)
* / % // 乘,除,取模和取整除
+ - 加法减法
>> << 右移,左移运算符
& 位 ‘AND’
^ | 位运算符
<= < > >= 比较运算符
<> == != 等于运算符
= %= /= //= -= += = *= 赋值运算符
is is not 身份运算符
in not in 成员运算符
not or and 逻辑运算符

优先级运算示例

  1. print(5 + 5 >> 2) # 先计算5 + 5=10 ,然后计算10 >> 2, 结果是2
  2. print(1 + 4 & 1) # 先计算1 + 4=5, 然后计算5 & 1, 结果是1
  3. print(3**2*4) # 先计算3**2 = 9,然后计算9*4, 结果是36
  4. a = 3
  5. a**= 2*2
  6. print(a) # 先计算2*2 = 4,然后计算3**4, 结果是

表达式

本篇文章共4个章节:

  1. 初学者是否有必要学习编程专业词汇
  2. 表达式的概念
  3. 表达式的应用
  4. 总结

    1. 初学者是否有必要学习编程专业词汇

    表达式是一个很专业的词汇,但凡是搞编程的,恐怕没有不理解的,即便说不出准确的定义,也能大概理解其中含义。对于初学者而言,有必要和这些专业词汇较劲么,我认为有必要。
    有些教程或者文章,喜欢用大白话讲解,固然可以降低初学者学习门槛,可是,编程本身是一项专业性很强的技术,所涉及到的概念,如果不能准确理解,正确使用,一开始影响倒也不大,因为你大多数时间都是在照猫画虎。但肯定会影响到你后续的学习,这是因为随着学习的深入,你遇到的问题变得复杂,复杂到不使用专业词汇就无法精准的定义和解释问题,大白话文章无法让你更上一层楼,你只能永远肤浅的入门,然后一辈子在一楼打转。

    2. 表达式的概念

    先来看百度百科里的定义:
    表达式,是由数字、算符、数字分组符号(括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合
    这个定义有点长,不好理解,咱们做个优化,将其总结为一个更短更容易理解的定义:表达式是可以被求值的代码
    有了这个定义,下面罗列一些表达式
    1. 4 > 5
    2. 3 == 3.0
    3. 'abc' == 'abc' and True
    4. 5
    5. (4 + 5)
    6. 5 >> 1
    7. 7 > 4 or (1 == 1 and 6 > 7)
    每一行都是一个表达式,他们有一个共同点,可以被求值,如果用print输出这些表达式,总能输出一个数值。

    3. 表达式的应用

    表达式的应用无处不在,如果没有表达式,也就没有编程这个事情了

    3.1 赋值语句

    这应该是表达式使用最多的场景了
    我们甚至可以粗暴的认为,所有赋值语句中,等号的右边都是表达式,在执行赋值语句时,先要计算等号右侧的表达式,将表达式的结果赋值给等号左侧的变量
    1. a = 3 > 4 or True
    a 最终的值为True

    3.2 if 语句

    1. if 表达式1:
    2. 语句块1
    3. elif 表达式2:
    4. 语句块2
    5. else:
    6. 语句块3
    紧跟在if 后面的部分(表达式1)就是表达式,当这个表达式的结果为True时,执行语句块1,否则判断紧跟在elif后面表达式2,如果表达式2的结果为True,则执行语句块2,如果前面的两个表达式的结果都是False,则最终执行语句块3。
    一些文章在讲述表达式为True时,会用表达式成立这样的说法,其实是一个意思。
    下面是程序流程图
    运算符与表达式 - 图1
    不论if语句中有多少个逻辑分支,永远只会进入其中一个,即便其他的表达式也是成立的,因为在执行if语句时,遵守短路原则,前面的判断语句如果成立了,后面的判断语句就不会被执行,相当于打麻将时的截胡。

    3.3 while 循环

    1. while 表达式A:
    2. 语句块A
    如果表达式A成立,则执行语句块A,语句块A执行结束后,会再次判断表达式A是否成立,成立继续执行语句块A,不成立,循环结束,下图为循环流程示意图
    运算符与表达式 - 图2

    3.4 函数返回值

    1. def add(a, b):
    2. return a + b
    上述代码中的a + b就是一个表达式,a + b的结果作为函数的返回值返回

    4.总结

    或许你觉得表达式太简单了,但编程就是由这些看似十分简单的概念构成的,不要认为简单就粗心大意,真的让你写程序时,恐怕你就不知道表达式该咋写了。