运算符
这部分知识较为基础且重要,文章介绍了不少的特殊情况,希望大家可以耐心看完,多多支持!
算术运算符
Python中,像 + - * / % ** //
这一系列的运算符称为算术运算符。
对于算术运算符,我们遵守计算的优先级:
- 括号
- 乘方
- 乘除
- 加减
对于 + - *
运算符没有值得补充的,只需要遵守优先级计算即可。
对于 /
运算符,要注意:
-
除数不能为0,0.0也不可以,程序会抛出异常,直接终止。(有些编程语言除以0会报错,除以0.0不会报错)
print(10 / 0)
print(10 / 0.0)
-
除法的截断问题,整数 / 整数,如果除不尽,直接得到小数,不会出现截断的问题.(除了Python以外的大部分语言,整数除以整数还是整数,就会发生截断)
print(1 / 2)
对于 %
运算符,是求余数
print(7 % 3)
运算符 **
是进行乘方运算或者开方运算
-
支持整数次方(乘方运算),也支持小数次方(开方运算)
print(2 ** 2) print(4 ** 0.5)
运算符 //
是进行地板除法(取整除法),会针对计算的结果进行 “向下取整”。
- 注意理解向下取整,特别是负数的向下取整,
-7 / 2 = 3.5
,那么//
向下取整是 -4 还是 -3 呢?
-4 < -3
,Python中会选择数值更小的 -4
print(7 // 2)
print(-7 // 2)
而在C语言中,则不太一样(C语言中没有 // 运算符):
#include <stdio.h>
int main()
{
printf("%d\n", 7 / 2);
printf("%d\n", -7 / 2);
return 0;
}
关系运算符
像 < <= > >= == !=
这一系列的运算符称为关系运算符。
它们是比较操作数之间的关系。
- <= 是 “小于等于”
- == 是 “等于”
- != 是 “不等于”
如果关系式符合,表达式返回True,如果关系不符合,则表达式返回False,这意味着,关系运算符对应的表达式,值是布尔类型
a = 10
b = 20
print(a < b)
print(a > b)
print(a >= b)
print(a <= b)
print(a == b)
print(a != b)
在Python中,连续的比较运算符是允许的,但是在C语言中编译会报错,但是不建议这样使用。
a1 = 1
a2 = 2
a3 = 10
print(a1 < a2 < a3)
a = 'a'
b = 'h'
c = 'y'
print(a < b < c)
关系运算还可以比较字符串,这与C语言不同,C语言不能直接使用 == 或 != 比较字符串大小,而要使用函数 strcmp比较,注意区分这一点。
字符串比较的规则:字典序
- 先看首字母在字母表上的顺序,谁排在前面谁就小
- 如果首字母相同,则依次比较剩余的字母
- 全部相等,则相等
- 字符的比较实际上是比较ASCII码值,字母的ASCII码值大小也是字典序。
a = 'hello'
b = 'world'
print(a < b)
print(a > b)
print(a >= b)
print(a <= b)
print(a == b)
print(a != b)
注意,比较时不要看字符串长度,例如:
b字符串的长度大于a字符串的长度,不过由于首字母 w 在 h 的后面,所以a字符串大于b字符串
a = 'world'
b = 'hello world'
print(a < b)
print(a > b)
print(a >= b)
print(a <= b)
print(a == b)
print(a != b)
空可以认为最小,因为没有嘛。
a = ''
b = 'a'
print(a < b)
print(a > b)
print(a >= b)
print(a <= b)
print(a == b)
print(a != b)
如果字符串是中文,那么比较将没有意义。不过,比较还是可以比较的,不会报错,在计算机里表示中文其实是用多个字节表示一个较大的数进行比较的。
字符串比较是大小写敏感的,所有小写的字母均大于所有的大写的字母。
a = 'z'
b = 'A'
print(a < b)
print(a > b)
print(a >= b)
print(a <= b)
print(a == b)
print(a != b)
针对浮点数来说,使用关系运算符是存在一定的风险的,因为浮点数在内存中的存储和表示,是可能存在误差的,这样的误差在进行算数运算的时候就可能被放大,导致误判。
例如:
print(0.1 + 0.2 == 0.3)
为什么呢? 我们不妨打印一下:
print(0.1)
print(0.2)
print(0.1 + 0.2)
print(0.3)
通过打印我们就能体会到浮点数的风险了。
这一点在C语言中也能体现
#include <stdio.h>
int main()
{
if (0.1 + 0.2 == 0.3)
{
printf("相等\n");
}
else
{
printf("不相等\n");
}
return 0;
}
同样通过打印观察:
#include <stdio.h>
int main()
{
if (0.1 + 0.2 == 0.3)
{
printf("相等\n");
}
else
{
printf("不相等\n");
}
return 0;
printf("%.20lf\n", 0.1);
printf("%.20lf\n", 0.2);
printf("%.20lf\n", 0.1 + 0.2);
printf("%.20lf\n", 0.3);
}
既然如此,我们怎么对浮点型数据进行比较呢?作差,看差值是否在我们可接受的范围,是否小于我们预期的误差范围
a = 0.1 + 0.2
b = 0.3
print(-0.000001 < (a - b) < 0.000001)
逻辑运算符
与C语言的&& || !
不同,Python中的逻辑运算符有三个:and or not
- and表示并且
- or 表示或者
- not 表示逻辑取反
and
(一假为假) 两侧操作符均为 True,表达式的值为 True,否则为 False。
a = 10
b = 20
c = 30
print(a < b and b < c) #等价于:print(a < b < c)
print(a < b and b > c)
or
(一真为真) 两侧操作数均为 False,表达式的值为 False,否则为 True
a = 10
b = 20
c = 30
print(a > b or b < c)
print(a > b or b > c)
not
只有一个操作数,操作数为 True,则返回 False;为 False,则返回 True
a = 10
b = 20
c = 30
print(not a < b)
print(not a > b)
逻辑运算符重要知识:短路问题(短路求值)
-
对于 and 操作符来说,如果左侧的表达式为 False,那么整体的值一定是 False,右侧表达式不必求值,直接结束。
-
对于 or 操作符来说,如果左侧的表达式为 True,那么整体的值一定是 True,右侧的表达式不必求值,直接结束。
以 and 为例:
a = 10
b = 20
print(a > b and 10 / 0 == 1)
我们前面介绍了,除运算符除数不能为0,如果右侧表达式求值,代码将出现异常。不过,按照我们的代码,左侧表达式为 False,出现短路现象,直接退出,将不计算右侧表达式。
结果并没有报错,验证了Python中的确存在短路求值。
赋值运算符
(1)=
的使用
=
就是最简单的赋值运算,注意与 关系运算符 ==
区分即可。
除了基本的用法之外,我们可以同时针对多个变量进行赋值:
-
链式赋值(一般不建议使用)
a = b = 10
-
多元赋值
a, b = 10, 20
实例:交换两个变量的值
a = 10
b = 20
# 使用第三个变量
tmp = a
a = b
b = tmp
print(f'第一次交换后 a = {a},b = {b}')
#基于多元赋值
a, b = b, a
print(f'第二次交换后 a = {a},b = {b}')
如果学过C语言,可能就会了解过函数的概念。Python中多元赋值还可以使函数返回多个值;而C语言不支持多元赋值,其函数也不可以返回多个值,这是两个语言的差别。
(2)复合赋值运算符
像+= -= /= *= %= **= //=
,都是复合赋值运算符。
a = 10
b = 10
a = a + 1
b += 1
print(a, b)
就像结果显示,a = a + 1
等价于 a += 1
,其他的复合赋值运算符类推。
注意! Python不支持 ++ 、-- 这样的自增、自减操作。
a = 10
++a;
print(a)
我们看到,++a
并没有报错,不过a也没有增加1变成11,这是因为Python编辑器将+看作是正号,对10前加两个正号,结果当然不变。 而写 后置++ --
将会报错!
位运算符
这类运算符需要一些有关数据的存储(原码、反码、补码等可以找我主页C专栏里的数据在内存中的存储篇)等前置知识。
位运算符包括:& | ^ ~ << >>
按位与运算符(&)
两个操作数对应的二进制位上的数如果都是1,那么这一位为1,否则为0。
按位或运算符(|)
两个操作数对应的二进制位上的数如果都是0,那么这一位为0,否则为1。
按位异或运算符(^)
两个操作数对应的二进制位上的数相同为0,不同为1(或者理解为:两个操作数对应的二进制位上的数只有一个1,结果为1,否则为0)
我们举个例子解释这三个例子:
a = 60
b = 13
print(a & b)
print(a | b)
print(a ^ b)
解释
Python中的 int 类型默认是4个字节的,4个字节就是4 × 8 = 32个比特位,相当于32个二进制位。
我们知道,整型的二进制表示有三种,原码、反码、补码,而整形数据是以补码存储在计算机里的。
正整数的原码、反码、补码相等,我们开始分析:
对于60,补码为00000000 00000000 00000000 00111100
对于13,补码为00000000 00000000 00000000 00001101
那么按照运算符的规则,可得:
按位取反运算符(~)
只有一个操作数,对其所有二进制位按位取反,0变1,1变0
左移操作符(<<)
将操作数的二进制位向左移动指定的位数,左移后低位补0
右移操作符(>>)
将操作数的二进制位向右移动指定的位数,右移后高位补0或1,这取决于参与运算的操作数的符号位
a = 60
b = 13
print(~a)
print(a << 1)
print(a >> 1)
我们画图解释:
成员运算符
想要了解清楚成员运算符,需要后续有关序列的知识,这里仅仅介绍运算符,后续会发布有关序列的博客,里面会再次讲到成员运算符。
常见的成员运算符有 in
和 not in
- in:判断一个值是否是一个序列的成员,是则返回 True,否则返回 False。
- not in:判断一个值是否不是一个序列的成员,不是则会返回 True,否则返回 False
a = [1, 2, 3, 4, 5]
print(3 in a)
print(100 not in a)
其实,我们的字符串,就是序列的一种,可以拿它举例子:
s = 'hello python'
print('l' in s)
print('o' not in s)
身份运算符
身份运算符 is
和 not is
用于比较两个对象的存储单元,返回值 为 True 或 False。
- is:判断两个标识符是不是引用自一个对象,如果是则返回 True,否则返回 False。
- not is:判断两个标识符是不是引用自不同对象,如果是则返回 True,否则返回 False。
在此之前,我们介绍一个函数 id() ,返回对象的内存地址。
a = 10
b = 10
print(id(a))
print(id(b))
print(a is b)
对于整型、浮点型、字符串:只要变量的类型和数值相同,它们id相同,是同一对象,指向内存同一地址。
a和b都是整型类型的变量,数值均为10,是同一对象,所以a is b
返回True
。
a = 10
b = 10.0
print(id(a))
print(id(b))
print(a is b)
a和b变量类型和数值均不同,不是同一对象。
区分 == 和 is
a = 10
b = 10.0
print(id(a))
print(id(b))
print(a is b)
print(a == b)
结论:is
判断是否引用自同一对象;==
判断值是否相等。
三目运算符
三目运算符通常用于简化条件判断语句。
鉴于没有介绍条件判断语句,我们直接给出代码:if 后面的语句为真则 if 前面的表达式的值为整个表达式的值,为假则 else 后面的表达式的值为整个表达式的值
a = 7
b = 10
print(a if a > b else b)
print(a if a != b else b)
优先级
其他知识补充
布尔类型可以和整数、浮点数执行一些算术运算的。
a = True
b = 10
c = 2.6
print(a + b)
print(a + c)
这是因为Python编辑器将True看作是1,False看作是0,不过这样的算术运算是没有意义的。
Python中是没有字符类型的!这与C语言不同。
正是因为Python中没有字符类型,所以单引号和双引号都可以表示字符串。像C/C++/Java,中是有单独的字符类型的,单引号表示字符类型,双引号表示字符串。
Python的语句末尾可以加上分号的,不会报错,不过通常不加。Python的分号也是有应用场景的,如果多个语句写在同一行,这时候语句之间务必加上分号,起到分隔语句的作用
下一节将会介绍Python中的语句!