这篇教程的标题图片有点文艺,作者今天刚分手,但是还是坐在电脑前面为了爱学习的小伙伴们,把教程敲下来了。
如果有那么多的如果,哪来那么多的是非对错
幸运的是 Python 世界没有如果,是非对错完全按照逻辑来走。如果你写了一个 Python 程序,而程序并没有往你设计的方向走,那一定是你写的逻辑出现了漏洞,而不是 Python 在闹情绪。
那接下来就来讲 Python 中如何做是非判断,和逻辑语法,在这之前先回顾之前的两篇教程:多多教Python:Python 基本功: 3. 数据类型zhuanlan.zhihu.com多多教Python:Python 基本功: 7. 介绍函数zhuanlan.zhihu.com
回顾数据类型是因为有一个特殊的基本数据类我没有提,就是 布尔 Boolean 类;回顾函数是因为书本上函数和逻辑是一起讲的,但是这里按照教程的节奏是分开来的。布尔 Boolean 类虽然看起来简单,但是在实际操作中,最容易出错出Bug的就是这个数据类了,所以有意的放在后面一点。
教程需求:Mac OS (Windows, Linux 会略有不同)
安装了 Python 3.0 版本以上, Anaconda
布尔 Boolean 类
布尔 Boolean 类是在 Python 逻辑处理中作为判断的根本依据。在 Python 中有两个数值,True 和 False, 下面我们打开 Anaconda Jupyter 笔记本来看例子:
In [1]: a = True
In [2]: type(a)
Out [2]: bool
In [3]: a == True
Out [3]: True
In [4]: a is True
Out [4]: True
In [5]: b = False
In [6]: a is b
Out [6]: False
In [7]: a == b
Out [7]: False
下面我们来分析一下每一行:定义了一个变量 a,是 True。
检查a 的类型,返回时 bool, 就是 布尔 Boolean 类。
"==" 是检查两个变量的值是否一致,这里 a 和 True 是一致的,所以返回 True。
"is" 是检查两个变量的内存地址是否一致,这里 a 和 True 的内存地址是一致的,后面会讲有关内存地址的检查。
新建立一个变量 b, 是 False。
a 和 b 的内存地址不一致,因为分别指向的 True 和 False 地址是不同的,返回 False。
检查两个变量的值是否一致,True 和 False 不一致,所以返回 False。
任何判断语句都会返回一个布尔 Boolean 类,然后通过逻辑语句来走向不同的代码区块 (code block)。现在我们来学习一下逻辑结构。
逻辑结构
Python 中支持三种基本逻辑结构: 顺承结构,分支结构和循环结构。这三种结构的混合使用可以实现所有的程序控制,现在我们一一讲一下这三种结构:顺承结构:A -> B -> C, 代码按照顺序执行下去,A代码区块运行的结果被用作B的代码的参数。
分支结构: A -> B 或者 A-> C, 从A 代码区块中根据判断出来的布尔类是 True 还是 False, 来执行 B 代码区块或者 C 代码区块。
循环结构:->A->B->A->B->,从 A 代码区块到 B 区块,然后再回到 A, 反复直到条件终止。
现在我们来看一些代码,表述了不同逻辑结构的语法:
a = 300
b = 600
if a < b or b % a == 0:
print("a小于b,或者b能被a整除")
elif a < b:
print("a小于b, 而且b不能被a整除")
elif a == b:
print("a的数值等于b")
else:
print("a大于b“)
这是一个典型的分支结构,这里先创建了两个变量 a 和 b。每一个逻辑内的代码区块都标注了中文解释,所以就不在这里做解释了,现在我们紧接着看下面一段:
count = 0
while True:
count += 1
if count >= 100:
print("到100个循环了,退出循环")
break
else:
print("还没到100循环,继续")
continue
print(count)
这是一个循环加分支结构。这里先创建了一个 count 变量来保存循环了多少次。While... [判断] 是一个无限循环语句,直到判断返还的是 False,这里 condition 就是 True, 所以退出循环依靠的是内部的分支结构。还有一种不依赖分支结构来退出循环的看下面:
count = 0
while count < 100:
count += 1
print(count)
这里 count < 100 是退出循环的判断,直到判断返回的是 False, 也就是 count >= 100的时候,循环就退出了。
a = [1, 2, 3, 4, 5]
for i in a:
print(i)
for j in range(10):
print(j)
if j > 6:
print("循环到6以后的数字就退出")
break
这里用到的是另一个循环语法, 通过 for ... in ... 语句来循环一个列表或者一个范围。这里变量 a 是一个列表,参见 多多教Python:Python 基本功: 3. 数据类型, 而 range(10) 是一个 0-9的数字范围,这里10代表从0开始数10个数字,所以不包括10。第二个循环里有一个分支用到了 break, 表示提前退出循环的意思。
(&,|)和(and,or)
这里是一个比较容易混淆的概念,同时也是之前提到的容易出Bug的地方:(&,|):在运算数值时,是在二进制当中进行位运算。在运算逻辑时,和 (and, or) 是一样的。
(and, or):在运算数值时,依据是否非0来决定输出。在运算逻辑时,和 (&, |) 是一样的。
下面我们来看运算数值时出现的情况:
1 & 2 # 输出 0,二进制运算
1 | 2 # 输出 3,二进制运算
2 and 0 # 输出 0,and 含0返还0
2 and 1 # 输出 1,均为非零返还后值
1 and 2 # 输出 2,均为非零返还后值
2 or 0 # 输出 2,返还非0
2 or 1 # 输出 2,至少有一个非0,返还第一个非0
0 or 1 # 输出 1
然后来看逻辑运算的情况:
(1 > 3) or (10 < 20) # 输出 True
(1 > 3) | (10 < 20) # 输出 True
(1 > 3) and (10 < 20) # 输出 False
(1 > 3) & (10 < 20) # 输出 False
在逻辑运算中结果是一致的。
is 和 ==
在比较两个变量数值是否相等时,用 "==";在比较两个变量的内存地址是否相等时,用 is。因为 Python 设计的理念是尽可能让变量成为指针,指向某一块内存,这样在变量操作的时候可以节省内存空间,速度更快。如果不学计算机的小伙伴可能比较难理解原理,但是没关系,在大多数情况你尽可能的比较两个变量的数值,用 "==" 就可以了。下面来看例子:
a = [1, 2, 3]
b = [1, 2, 3]
c = a
a == b # 输出 True, 因为数值一样
a is b # 输出 False, 虽然列表内数值一样,但是是两个列表,内存地址不一样。
c is a # 输出 True, c 是一个新的变量,指向a的地址,所以 c 就是 a。
c.append(4)
a # 输出 [1, 2, 3, 4], 因为 c 就是 a, 所以改变c也改变了a。
d = a.copy()
d is a # 输出 False, 因为d 是 a 的一个拷贝,而拷贝出来的是属于一个新的内存地址,所以d和a指向的不是同一个地址。
这里可能比较难的就是最后一段,d 拿到了 a 的拷贝之后,就和 a 的内存地址不一样了。不明白没关系,基本要知道的是 Python 会尽可能的通过指针的指向来改变变量的数值,除非你强制性的用拷贝 copy() 来增加新的变量。 这个会在之后的关于Python 如何管理内存空间的教程中讲到。
运算符重载
前文运用的包括 "<, >, ==, &, |, and, or ..." 都属于运算符。在基础数据类中,两个数据值的比较是被规范定义的,比如说 1 < 2。而在比较一些非常规的数值的时候,比较方式就需要自己去规范定义,这就是运算符重载 (operator overload)。
a = [1, 2, 3, 4]
b = [1, 2, 3, 4, 5]
c = set(1, 2, 3, 4)
a > b # 返回 False,列表比较在 Python 中定义了,但是你不去查就不知道具体如何比较。
len(a) > len(b) # 返回 False, 这样比较更显而易见,b 比 a 长,多一个元素。
c > a # 报错,因为没有定义如何比较列表和集合。
因为这部分需要先了解类,和虚拟函数,所以会在下面两篇先覆盖这两个内容,然后再回到这里。
小结:
本篇的内容还是很多的,有讲逻辑结构,运算符,和提到了运算符重载。判断是非是Python中最容易出Bug的地方,几乎大多数都是判断语句出错,逻辑失效然后导致了整个程序没有往设计的方向运行。所以对待逻辑判断要细致入微才可以。接下来放两个外部链接,提供了额外的例子:
外部的介绍 Python 的内存管理:Python内存管理及释放 - jiangjiane - CSDN博客blog.csdn.net
Python 中 is 和 ==的区别:Python is 与 == 区别www.runoob.com