一、概念:
运算符:运算符用于执行程序代码运算,会针对一个以上操作数项目来进行运算。比如10+4=14,其中操作数是 10 和 4,运算符是“+” 。 Python 语言主要支持运算符类型有:算术运算符、比较(关系)运算符、赋值运算符、逻辑运算符、位运算运算符、成员运算符以及身份运算符。
表达式:将不同类型的数据,比如常量、变量、字典、函数等,用运算符按照一定的规则链接起来的式子。比如,算数表达式,又被称为数值表达式,x*y,举例 8*9 =72。
二、算术运算符:
算术运算符主要包括了四则运算、求模等,如下,假设a,b是两个变量
运算符 | 表达式 |
描述 |
+ | a + b |
相加 |
- | a - b |
相减 |
* | a * b |
相乘 |
/ | a / b |
相除 |
% | a % b |
求余数 |
** | a ** b |
a的b次方 |
// | a // b |
a除以b求商 |
三、比较运算符
运算符 |
表达式 | 描述 |
== |
a == b | 比较两个对象是否想等,相等则返回True,否则返回False |
!= |
a != b | 比较两个对象是否不相等,不相等则返回True,否则返回False |
> |
a > b | a 大于 b则True,否则False |
< |
a < b | a 小于 b则True,否则False |
>= |
a >= b | a 大于或等于 b则True,否则False |
<= |
a <= b | a 小于或等于 b则True,否则False |
四、赋值运算符
赋值运算符是把简单的赋值运算符与算术运算符结合,为了使简化写法。比如 +=,便是加法赋值运算符,意思是先执行加法,然后赋值。例子 a+=b 等价于 c= a +b ;a= c 或者 a = a+b。具体的赋值运算符,如下表所示,a b 为两个变量。
运算符 |
表达式 | 描述 |
= |
c=a+b | 基础赋值运算符 |
+= |
a+=b<=>a = a+b | 加法赋值运算符 |
-= |
a-=b<=>a=a-b | 减法赋值运算符 |
*= |
a*=b<=>a=a*b | 乘法赋值运算符 |
/= |
a/=b<=>a=a/b | 除法赋值运算符 |
%= |
a%=b<=>a=a%b | 取模赋值运算符 |
**= |
a**=b<=>a=a**b | 幂赋值运算符 |
//= |
a//=b<=>a=a//b | 取整赋值运算符 |
五、按位运算符
运算符 |
表达式 | 描述 |
& | a &b | 按位与运算符:参与运算的两个值,如果两个相应位都为 1,则该位 的结果为 1,否则为 0 |
| | a|b | 按位或运算符:只要对应的二个二进位有一个为 1 时,结果位就 为 1。 |
^ | a^b | 按位异或运算符:当两对应的二进位相异时,结果为 1 |
~ | ~a | 按位取反运算符:对数据的每个二进制位取反,即把 1 变为 0,把 0 变为 1。 ~x 类似于 -x-1 |
<< | a <<2 | 左移动运算符:运算数的各二进制位全部左移若干位,由"<<"右边 的数指定移动的位数,高位丢弃,低位补 0。 |
>> | a >>2 | 右移动运算符:把">>"左边的运算数的各二进位全部右移若干 位,">>"右边的数指定移动的位数 |
按位运算就把数字转换为机器语言——二进制的数字来运算的一种运算形式。例子如下:
# 与 1010 & 1100 = 1000 # 或 1010 | 1100 = 1110 # 异或 1010 ^ 1100 = 0110 # 左移 1010 << 2 = 101000 # 右移 1010 >> 2 = 10 # 非 ~1010 = 0101
单纯的二进制位之间的这些运算相当简单,但对我们实际编程并没有直接帮助,因为编程过程中需要的经常是数字间的运算,比如 5*(2^4) 。
在计算机系统中,数值一律用补码来表示、运算和存储。使用补码,可以将符号位和数值域统一处理,将加法和减法统一处理。此外,补码与原码相互转换,其运算过程是相同
的,不需要额外的硬件电路。详细的解释可以参考原码, 反码, 补码详解。
0b1010 & 0b1100 8 #1000 0b1010 | 0b1100 14 #1110 0b1010 ^ 0b1100 6 #0110 0b1010 << 2 40 #101000 0b1010 >> 2 2 #10 ~0b1010 -11 #10000000 00000000 00000000 00001011 type(0b1010) <type 'int'>
上面0b开头的0、1串表示整型数字,在32位操作系统中,Python中int类型一般占32个二进制位,以最后一个求反运算为例子,1010的补码为
00000000 00000000 00000000 00001010
求反操作后为:
11111111 11111111 11111111 11110101
为-11(原码为:10000000 00000000 00000000 00001011
)的补码。(对一个数的补码求补码即可得到该数的原码)
几个技巧点:(1)利用按位与可以将任意二进制数的最后一位变为0,即就是X&0;
(2)利用按位并可以将任意二进制数的最后一位变为1,即就是X|1;
按位运算的实际应用
1、不用第三个变量实现两个数字互换
# 定义一个函数,利用异或运算,将两个变量的值进行对调 def swap(num_1, num_2): num_1 ^= num_2 num_2 ^= num_1 num_1 ^= num_2 return num_1, num_2 # 随机赋值两个数分别给a和b a = 10 b = 59 print('使用函数前a和b分别是',a,b) print('使用函数后a和b分别是:',swap(a,b))
证明很简单,我们只需要明白异或运算满足下面规律:
- 0^a = a;
- a^a = 0;
- a^b^c = a^c^b;
2、不使用除法判断一个数字是奇数还是偶数
# 定义一个判断一个数是奇数还是偶数的函数,这里利用到的知识是按位与 def IsOdd(a): if a & 1 : print(a,'是奇数') else: print(a,'是偶数') # 调用函数 IsOdd(1) ''' 用位运算判断一个数是奇数还是偶数: 1、只需判断最后一位是1还是0 2、最后一位是1,说明是奇数。最后一位是0,说明是偶数 3、因为只有2的0次方才是奇数值1,其他的2的k(k = 1,2,….)都是偶数 '''
六、逻辑运算符
逻辑运算符主要是 and or 等。 具体的位运算符如下表所示, a b 为两个变量
运算符 | 表达式 | 描述 |
and | a and b | 布尔"与" . 如果 a 为 False,a and b 返回 False,否则它返回 b 的计算值。 |
or | a or b | 布尔"或" - 如果 a 是 True,它返回 a 的值,否则它返回 b 的计算 值。 |
not | not a | 布尔"非" - 如果 a 为 True,返回 False 。如果 a 为 False,它返 回 True。 |
七、成员运算符
成员运算符是判断一个变量的值是不是另外一个的一部分,变量的类型可以是字符串、列表或元组等。 具体的成员运算符如下表所示, a b 为两个变量
运算符 | 表达式 | 描述 |
in | a 在 b 序列中 , 如果 a 在 b 序列中返回 True。 |
如果在指定的序列中找到一 个变量的值,则返回 true,否则返回 false。 |
not in | a 不在 b 序列中 , 如果 a 不 在 b 序列中返回 True。 |
如果在指定序列中找不到变 量的值,则返回 true,否 则返回false。 |
八、身份运算符
身份运算符是用来比较两个对象是否为同一个对象,也就是判断两个变量引用对象是否为同一个。。而之前比较运算符中的 == 则是用来比较 2 个对象的值是否相等。在
Python 中,每一个变量有 3 个属性:name、 id、 value。
name 是变量名;内存的名称就是变量名。实质上,内存数据都是以地址来标识的,根本没有内存的名称这个说法,这只是高级语言提供的抽象机制 ,方
便我们操作内存数据
id 是查看该对象所在内存地址,内存的地址用于标识这个内存块
value 是变量的值。 内存的数据就是变量的值对应的二进制,一切都是二进制
身份运算符则是通过这个 id 来进行判断的,id 一样就返回 true,否则返回 false。但是对于小的整数,Python 缓存了-5 到 257 之间的所有整数,共262 个。 如果对象的类型为
整数或字符串且值一样,则 x == y 和 x is y 的值都为 True。(经测试浮点型数值,只有正浮点数符合这条规律,负浮点数不符合);如何对象是列表、字典、集合等,x is y 则为
False;
运算符 | 表达式 | 描述 |
is | a is b, 类似 id(a) == id(b) , 如果引用的是同一 个对象则返回 True |
is 是判断两个标识符是不是 引用自一个对象 |
is not |
a is not b ,类似 id(a) != id(b)。如果引用的不是 同一个对象则返回结果 True |
is not 是判断两个标识符是不 是引用自不同对象 |
将一个变量的值赋值给另一个变量,其实就是将这两个变量指向同一个内存地址。所以如果这个变量的值改变了,那么另一个变量的值也会跟着改变,因为它们的内存地
址始终相同。
浅拷贝和深拷贝
为了让一个对象发生改变时,不对原对象产生副作用(也就是互不影响),此时,需要一份这个对象的拷贝,python 提供了 copy 机制来完成这样的任务,对应的模块是
copy。拷贝分为浅 copy 与深拷贝。浅拷贝就是创建一个具有相同类型,相同值但不同 id 的新对象。浅拷贝仅仅对对象自身创建了一份拷贝,而没有在进一步处理对象中包含的子对
象值(比如列表,字典等子对象。也就是说浅拷贝对子对象不起作用,其中一个变量的子对象值被修改了,另外一个也跟着被修改。因此使用浅拷贝的典型使用场景是:对象自身发
生改变的同时需要保持对象中的值完全相同,比如 list 排序。
深拷贝不仅仅拷贝了原始对象自身,也对其包含的值进行拷贝,它会递归的查找对象中包含的其他对象的引用,来完成更深层次拷贝。拷贝完成以后,两个变量为完全独立的对
象,互不影响。因此,深拷贝产生的副本可以随意修改而不需要担心会引起原始值的改变。
# 浅拷贝 import copy # 导入 copy模块 a = [7, 5, 6, ['m', 'o', 'p']] b = copy.copy(a) # a.copy() print(id(a), id(b)) print(a is b) print(F'a,{a}与 b,{b}有一样的值 ') a.append(10) print("浅 COPY是值互不影响 ") print(id(a), id(b)) print('a被修改为: ',a) print('b没有被修改',b) a[3].append('new') print("浅 COPY不能 COPY自对象的值, a的子对象修改了, b也跟着修改 ") print(id(a), id(b)) print('a的值也被修改为:',a) print('b的值也被修改为:',b) print(a is b) print(a[3] is b[3]) # 结果如下: ''' 4528962568 4528970824 False a,[7, 5, 6, ['m', 'o', 'p']]与 b,[7, 5, 6, ['m', 'o', 'p']]有一样的值 浅 COPY是值互不影响 4528962568 4528970824 a被修改为: [7, 5, 6, ['m', 'o', 'p'], 10] b没有被修改 [7, 5, 6, ['m', 'o', 'p']] 浅 COPY不能 COPY自对象的值, a的子对象修改了, b也跟着修改 4528962568 4528970824 a的值也被修改为: [7, 5, 6, ['m', 'o', 'p', 'new'], 10] b的值也被修改为: [7, 5, 6, ['m', 'o', 'p', 'new']] False True ''' # 深拷贝 print('深拷贝的例子 ') a = [7, 5, 6, ['m', 'o', 'p']] b = copy.deepcopy(a) print(id(a), id(b)) print(a is b) print(F'a,{a}与 b,{b}有一样的值 ') a.append(10) print("深 COPY是值互不影响 ") print(id(a), id(b)) print('a被修改为: ',a) print('b没有被修改',b) a[3].append('new') print("深拷贝的子对象不会被拷贝 ") print(id(a), id(b)) print('a的值也被修改为:',a) print('b的值也被修改为:',b) print(a is b) print(a[3] is b[3]) # 结果如下: ''' 深拷贝的例子 4526931464 4526922760 False a,[7, 5, 6, ['m', 'o', 'p']]与 b,[7, 5, 6, ['m', 'o', 'p']]有一样的值 深 COPY是值互不影响 4526931464 4526922760 a被修改为: [7, 5, 6, ['m', 'o', 'p'], 10] b没有被修改 [7, 5, 6, ['m', 'o', 'p']] 深拷贝的子对象不会被拷贝 4526931464 4526922760 a的值也被修改为: [7, 5, 6, ['m', 'o', 'p', 'new'], 10] b的值也被修改为: [7, 5, 6, ['m', 'o', 'p']] False False '''
九、运算符优先级
运算符的优先级决定了计算顺序,以下表格列出了从最高到最低优先级的所有运算符。但是我们不需要死记硬背,在项目中我们有时候可以使用()方法来提供弱优先级,达到优
先执行,并且添加了括号,程序可读性也好很多。
运算符 |
描述 |
** | 指数 (最高优先级) |
~ + - | 按位翻转, 一元加号和减号 (最后两个的方 法名为 +@ 和 -@) |
* / % // | 乘,除,取模和取整除 |
+ - | 加法减法 |
>> << | 右移,左移运算符 |
& | 位 'AND' |
^ | | 位运算符 |
<= < > >= | 比较运算符 |
<> == != | 等于运算符 |
= %= /= //= -= += *= **= | 赋值运算符 |
is is not | 身份运算符 |
in not in | 成员运算符 |
and or not | 逻辑运算符 |
# 优先级 number = 2*2**3 # 幂的优先级大于乘法 print("number is ",number) number = (2*2)**3 # 使用括号更改优先级顺序 print('使用()优先级以后, number is' , number) ''' 结果为: number is 16 使用()优先级以后, number is 64 '''