Python 中的运算符以及流程控制

前面已经了解了 Python 中常用的数据结构,本文接着来看 Python 中的运算符以及程序流程控制,这是一个 可执行 Python 程序实现的必要部分。

前面我们已经熟悉并深入了解了 Python 支持的六种基本数据类型,这就意味着我们已经成功突破现实世界和镜像世界数据差异的墙。

但对于 Python 世界而言,光掌握正确使用 【镜像世界的数据】 还不够,还需要正确的 【沟通逻辑】 才能让Python 准确地执行我们下达的命令,这就需要了解 Python 中的运算符以及流程控制以帮助我们完成更多的功能。


Python 中的运算符

开始后续的流程控制学习之前,我们需要系统的认识一下 Python 中的运算符。

我们先来看个简单的例子:

1
2
>>> 4 + 5
9

其中 45 被称为操作数,+ 被称之为运算符。

Python 语言支持以下类型的运算符:

  • 算术运算符
  • 赋值运算符
  • 比较(关系)运算符
  • 逻辑运算符
  • 位运算符
  • 成员运算符
  • 身份运算符

本文将会针对上述运算符分类,进行分别学习:

运算符详解

算术运算符

在介绍 Number(数字)数据类型时,我们已经接触过算术运算了。这里我们来看如何使用算术运算符进行算术运算:

[1] >>>> 加法:

1
2
3
4
5
6
7
8
>>> aNumber = 21
>>> bNumber = 10
>>> cNumber = 0

# 加法:
>>> cNumber = aNumber + bNumber
>>> print("The value of cNumber:",cNumber)
The value of cNumber: 31

+ 用于数字(Number)时表示加法运算(加法运算符);但是当 + 用于序列时表示连接运算(连接运算符),请参照 Python 中的序列说明。

[2] >>>> 减法:

1
2
3
>>> cNumber = aNumber - bNumber
>>> print("The value of cNumber:",cNumber)
The value of cNumber: 11

- 除了可以用作减法运算之外,还可以用作求负运算(正数变负数,负数变正数),即取相反数。

[3] >>>> 乘法:

1
2
3
>>> cNumber = aNumber * bNumber
>>> print("The value of cNumber:",cNumber)
The value of cNumber: 210

* 用于数字(Number)时表示乘法运算(乘法运算符);但是当 * 用于序列时表示重复运算(重复运算符),用于将几个同样的序列连接起来,请参照 Python 中的序列说明。

[4] >>>> 除法:

1
2
3
4
5
6
7
8
9
10
11
12
# 普通除法(计算结果总是小数,不管是否能除尽,也不管参与运算的是整数还是浮点数):
>>> aNumber = 21
>>> bNumber = 10
>>> cNumber = 0
>>> cNumber = aNumber / bNumber
>>> print("The value of cNumber:",cNumber)
The value of cNumber: 2.1

# 整除(直接舍弃小数部分):
>>> cNumber = aNumber // bNumber
>>> print("The value of cNumber:",cNumber)
The value of cNumber: 2

注意:进行除法运算时,除数始终不能为 0,除以 0 是没有意义的,这将导致 ZeroDivisionError 错误。在某些编程语言中,除以 0 的结果是无穷大(包括正无穷大和负无穷大)。

[5] >>>> 取模(取余):

1
2
3
4
5
6
>>> aNumber = 21
>>> bNumber = 10
>>> cNumber = 0
>>> cNumber = aNumber % bNumber
>>> print("The value of cNumber:",cNumber)
The value of cNumber: 1

[5] >>>> 幂运算:

1
2
3
4
5
6
>>> aNumber = 21
>>> bNumber = 10
>>> cNumber = 0
>>> cNumber = aNumber ** bNumber
>>> print("The value of cNumber:",cNumber)
The value of cNumber: 16679880978201

赋值运算符

运算符 描述 实例
= 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c
+= 加法赋值运算符 c += a 等效于 c = c + a
-= 减法赋值运算符 c -= a 等效于 c = c - a
*= 乘法赋值运算符 c *= a 等效于 c = c * a
/= 除法赋值运算符 c /= a 等效于 c = c / a
%= 取模赋值运算符 c %= a 等效于 c = c % a
**= 幂赋值运算符 c **= a 等效于 c = c ** a
//= 取整除赋值运算符 c //= a 等效于 c = c // a

通常情况下,只要能使用扩展后的赋值运算符,都推荐使用这种赋值运算符。

注意:=== 是两个不同的运算符。= 用来赋值,而 == 用来判断两边的值是否相等,千万不要混淆。


位运算符

位运算符是把数字看作二进制来进行计算的。Python 中的按位运算法则如下:

  • &:按位与运算符:参与运算的两个值,如果两个相应位都为 1,则该位的结果为1,否则为 0;
  • |:按位或运算符:只要对应的二个二进位有一个为 1 时,结果位就为 1;
  • ^:按位异或运算符:当两对应的二进位相异时,结果为 1 ;
  • ~:按位取反运算符:对数据的每个二进制位取反,即把 1 变为 0,把 0 变为 1;
  • <<:左移动运算符:把 “<<” 左边的运算数各二进位全部左移若干位,”<<” 右边的数用来指定移动的位数,高位丢弃,低位补 0;
  • >>:右移动运算符:把 “>>” 左边的运算数的各二进位全部右移若干位,”>>” 右边的数指定移动的位数。

代码演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>>> aNumber = 60            # 60 = 0011 1100
>>> bNumber = 13 # 13 = 0000 1101
>>> cNumber = 0

>>> cNumber = aNumber & bNumber; # 12 = 0000 1100
>>> print ("1.cNumber 的值为:", cNumber)
1.cNumber 的值为: 12

>>> cNumber = aNumber | bNumber; # 61 = 0011 1101
>>> print ("2.cNumber 的值为:", cNumber)
2.cNumber 的值为: 61

>>> cNumber = aNumber ^ bNumber; # 49 = 0011 0001
>>> print ("3.cNumber 的值为:", cNumber)
3.cNumber 的值为: 49

>>> cNumber = ~aNumber; # -61 = 1100 0011
>>> print ("4.cNumber 的值为:", cNumber)
4.cNumber 的值为: -61

>>> cNumber = aNumber << 2; # 240 = 1111 0000
>>> print ("5.cNumber 的值为:", cNumber)
5.cNumber 的值为: 240

>>> cNumber = aNumber >> 2; # 15 = 0000 1111
>>> print ("6.cNumber 的值为:", c)
6.cNumber 的值为: 15

比较(关系)运算符

运算符 说明
> 大于,如果>前面的值大于后面的值,则返回 True,否则返回 False。
< 小于,如果<前面的值小于后面的值,则返回 True,否则返回 False。
== 等于,如果==两边的值相等,则返回 True,否则返回 False。
>= 大于等于(等价于数学中的 ≥),如果>=前面的值大于或者等于后面的值,则返回 True,否则返回 False。
<= 小于等于(等价于数学中的 ≤),如果<=前面的值小于或者等于后面的值,则返回 True,否则返回 False。
!= 不等于(等价于数学中的 ≠),如果!=两边的值不相等,则返回 True,否则返回 False。

实例如下:

1
2
3
4
5
6
7
8
>>> print("89是否大于100:", 89 > 100)
89是否大于100: False
>>> print("24*5是否大于等于76:", 24*5 >= 76)
24*5是否大于等于76: True
>>> print("86.5是否等于86.5:", 86.5 == 86.5)
86.5是否等于86.5: True
>>> print("34是否等于34.0:", 34 == 34.0)
34是否等于34.0: True

逻辑运算符

Python 语言支持的逻辑运算符如下:

  • a and b:等价于数学中的“且”,a 和 b 两个表达式都真为真,有假即假;
  • a or b:等价于数学中的“或”,a 和 b 两个表达式有真即真,都假即假;
  • not a:等价于数学中的“非”,如果 a 为真,那么 not a 的结果为假;如果 a 为假,那么 not a 的结果为真。相当于对 a 取反。

故,逻辑运算符一般和关系运算符结合使用,例如:

1
2
3
4
5
6
7
8
9
10
>>> age = int(input("请输入年龄:"))
请输入年龄:23
>>> height = int(input("请输入身高:"))
请输入身高:178
>>> if age>=18 and age<=30 and height >=170 and height <= 185 :
... print("恭喜,你符合报考飞行员的条件")
... else:
... print("抱歉,你不符合报考飞行员的条件")
...
恭喜,你符合报考飞行员的条件

注意,Python 逻辑运算符可以用来操作任何类型的表达式,不管表达式是不是 bool 类型;同时,逻辑运算的结果也不一定是 bool 类型,它也可以是任意类型。

逻辑运算符的本质 >>>>

对于 and 运算符,两边的值都为真时最终结果才为真,但是只要其中有一个值为假,那么最终结果就是假,所以 Python 按照下面的规则执行 and 运算:

  • 如果左边表达式的值为假,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是假,此时 and 会把左边表达式的值作为最终结果;

  • 如果左边表达式的值为真,那么最终值是不能确定的,and 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。

对于 or 运算符,情况是类似的,两边的值都为假时最终结果才为假,只要其中有一个值为真,那么最终结果就是真,所以 Python 按照下面的规则执行 or 运算:

  • 如果左边表达式的值为真,那么就不用计算右边表达式的值了,因为不管右边表达式的值是什么,都不会影响最终结果,最终结果都是真,此时 or 会把左边表达式的值作为最终结果。
  • 如果左边表达式的值为假,那么最终值是不能确定的,or 会继续计算右边表达式的值,并将右边表达式的值作为最终结果。

使用代码验证上面的结论:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Python 中,所有的对象都可以进行真假值的测试,包括字符串、元组、列表、字典、对象
# 条件判断中以下数值会被认为是 False:
# 为零的数:0 or 0.0;
# 空字符串:'',"";
# 空值:None;
# 空集合:(),[],{};
# 其他的值都认为是 True。

url = "hello, pretty girl!"

print("----False and xxx-----")
print( False and print(url) )
print("----True and xxx-----")
print( True and print(url) )
print("----False or xxx-----")
print( False or print(url) )
print("----True or xxx-----")
print( True or print(url) )

运行看一下:

1
2
3
4
5
6
7
8
9
10
----False and xxx-----
False
----True and xxx-----
hello, pretty girl!
None
----False or xxx-----
hello, pretty girl!
None
----True or xxx-----
True

成员运算符

除了以上的一些运算符之外,Python 还支持成员运算符。正如我们在字符串(str),列表(list)或元组(tuple)、字典(dict)、集合(set)中进行的成员检查。

  • in:如果在指定的序列中找到值返回 True,否则返回 False;
  • not in:如果在指定的序列中没有找到值返回 True,否则返回 False。

关于成员运算符的使用请参考前面字符串(str),列表(list)或元组(tuple)、字典(dict)、集合(set)部分。


身份运算符

身份运算符用于比较两个对象的存储单元:

  • is:is 判断两个变量所引用的对象是否相同,如果相同则返回 True,否则返回 False。
  • is not:is not 判断两个变量所引用的对象是否不相同,如果不相同则返回 True,否则返回 False。
    注意,id([object])函数用于获取对象的内存地址。

下面我们来看身份运算符如何使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
>>> aNumber = 20
>>> bNumber = 20

>>> if ( aNumber is bNumber ):
... print ("1 - aNumber 和 bNumber 有相同的标识")
... else:
... print ("1 - aNumber 和 bNumber 没有相同的标识")
...
1 - aNumber 和 bNumber 有相同的标识
>>> if ( id(aNumber) == id(bNumber) ):
... print ("2 - aNumber 和 bNumber 有相同的标识")
... else:
... print ("2 - aNumber 和 bNumber 没有相同的标识")
...
2 - aNumber 和 bNumber 有相同的标识


# 修改变量 b 的值
>>> bNumber = 30
>>> if ( aNumber is bNumber ):
... print ("3 - aNumber 和 bNumber 有相同的标识")
... else:
... print ("3 - aNumber 和 bNumber 没有相同的标识")
...
3 - aNumber 和 bNumber 没有相同的标识
>>> if ( aNumber is not bNumber ):
... print ("4 - aNumber 和 bNumber 没有相同的标识")
... else:
... print ("4 - aNumber 和 bNumber 有相同的标识")
...
4 - aNumber 和 bNumber 没有相同的标识

三目运算符

除了上面介绍的基本运算符之外,Python 中还支持使用 if else 实现类似于其它编程语言中三目(三元)运算符 ? :,语法如下:

1
exp1 if contion else exp2

说明 >>>>

condition 是判断条件,exp1 和 exp2 是两个表达式。如果 condition 成立(结果为真),就执行 exp1,并把 exp1 的结果作为整个表达式的结果;如果 condition 不成立(结果为假),就执行 exp2,并把 exp2 的结果作为整个表达式的结果。

看下面的例子:

1
2
3
4
5
>>> a = 3
>>> b = 4
>>> max = a if a>b else b
>>> print(max)
4

Python 三目运算符还支持嵌套,如此可以构成更加复杂的表达式。在嵌套时要需要注意 if 和 else 的配对:

1
a if a>b else c if c>d else d

但为了保持代码的可读写,建议不要嵌套太多的三元运算符!


运算符优先级

以下给出出了从最高到最低优先级的所有运算符:

**:指数 (最高优先级)】–>

~ + -:按位取反, 一元加号和减号 (表示正负号)】–>

* / % //:乘,除,取模和取整除】–>

+ -:加法减法】–>

>> <<:右移,左移运算符】– >

& ^ |:位与,异或,位或】–>

<= < > >=:关系】–>

== !=:等于运算符】–>

= %= /= //= -= += *= **=:赋值运算符】–>

is is not:身份运算符】–>

in not in:成员运算符】–>

and or not:逻辑运算符】。


Python 中的流程控制结构

和其它编程语言一样,按照执行流程划分,Python 程序也可分为三大结构,即顺序结构、选择(分支)结构和循环结构:

  • 顺序结构:让程序按照从头到尾的顺序依次执行每一条 Python 代码,不重复执行任何代码,也不跳过任何代码;
  • 选择结构:也称分支结构,就是让程序“拐弯”,有选择性的执行代码;换句话说,可以跳过没用的代码,只执行有用的代码;
  • 循环结构,就是让程序“杀个回马枪”,不断地重复执行同一段代码。

分支结构

Python 中,可以使用 if else 语句对条件进行判断,然后根据不同的结果执行不同的代码,这称为 选择结构 或者 分支结构

分支结构形式

Python 中的 if else 语句可以细分为三种形式,分别是 if 语句if else 语句if elif else 语句

[1] >>>> 单向判断

单项判断是最简单的分支结构,表示:”如果……就……“,其流程图如下所示:

代码实例如下:

1
2
3
4
5
6
age = 20
if age >= 18:
# 条件满足时,做点什么:
print("You are a man.")

print("Continue Run")

[2] >>>> 双向判断

双向判断可以帮助我们解决更为复杂的判断,表示:如果……就……,否则的话……,其流程图如下所示:

代码实例如下:

1
2
3
4
5
6
7
8
9
10
11
age = 20
if age >= 18:
# 条件满足时,做点什么:
print('your age is', age)
print('adult')
else:
# 当 if 条件不满足时,做的其它什么:
print('your age is', age)
print('teenager')

print("Continue Run")

根据 Python 的缩进规则,如果 if 语句判断是 True,就把 if 缩进下的两行 print 语句执行了。否则执行 else 下的缩进代码块。

[3] >>>> 多向判断

事实上,上面的判断是很粗略的,完全可以用 if...elif...else... 实现更复杂判断,其流程图如下所示:

Python 会从上到下逐个判断表达式是否成立,一旦遇到某个成立的表达式,就执行后面紧跟的语句块,此时,剩下的代码就不再执行了,不管后面的表达式是否成立。如果所有的表达式都不成立,就执行 else 后面的代码块。

代码结构如下:

1
2
3
4
5
6
if condition_1:
statement_block_1
elif condition_2:
statement_block_2
else:
statement_block_3

另外注意,Python 中是没有 switch – case 语句的。

并且当多向判断条件比较多时,可以通过数轴进行包含关系判断,这是很有用的。


if 语句嵌套

上面详细介绍了 3 种形式的条件语句,即 if、if else 和 if elif else,这 3 种条件语句之间可以相互嵌套。例如:

1
2
3
4
5
6
7
8
9
10
11
12
if 表达式1:
语句
if 表达式2:
语句
elif 表达式3:
语句
else:
语句
elif 表达式4:
语句
else:
语句

当然,嵌套使用上很灵活。你还可以;

1
2
3
4
5
6
7
8
if 表达式1:
语句
if 表达式2:
语句
elif 表达式4:
语句
else:
语句

事实上,嵌套的关键在于你要分清楚各判断层的逻辑,由外向内一层层分析,就像剥洋葱一样。


空语句 pass

在实际开发中,有时候我们会先搭建起程序的整体逻辑结构,但是暂时不去实现某些细节,而是在这些地方加一些注释,方面以后再添加代码,请看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
age = int( input("请输入你的年龄:") )
if age < 12 :
print("婴幼儿")
elif age >= 12 and age < 18:
print("青少年")
elif age >= 18 and age < 30:
print("成年人")
elif age >= 30 and age < 50:
#TODO: 成年人
else:
print("老年人")

当年龄大于等于 30 并且小于 50 时,我们没有使用 print() 语句,而是使用了一个注释(#TODO),希望以后再处理成年人的情况。当 Python 执行到该 elif 分支时,会跳过注释,什么都不执行。

Python 提供了一种更加专业的做法,就是空语句 pass,用来让解释器跳过此处,什么都不做。

就像上面的情况,有时候程序需要 占一个位置,或者放一条语句,但又不希望这条语句做任何事情,此时就可以通过 pass 语句来实现。使用 pass 语句比使用注释更加优雅。如下:

1
2
3
4
5
6
7
8
class MyEmptyClass:
pass

def nop():
pass

if age >= 18:
pass

断言函数 assert

assert 语句,又称断言语句,语法结构为:

1
assert 表达式

可以看做是功能缩小版的 if 语句,它用于判断某个表达式的值,如果值为真,则程序可以继续往下执行;反之,Python 解释器会报 AssertionError 错误。

assert 语句的执行流程可以用 if 判断语句表示,如下所示:

1
2
3
4
if 表达式==True:
程序继续执行
else:
程序报 AssertionError 错误

有读者可能会问,明明 assert 会令程序崩溃,为什么还要使用它呢?这是因为,与其让程序在晚些时候崩溃,不如在错误条件出现时,就直接让程序崩溃,这有利于我们对程序排错,提高程序的健壮性。

assert 语句通常用于检查用户的输入是否符合规定,或者限定函数参数类型等。如下:

1
2
3
4
5
6
7
8
9
def func(input):
assert isinstance(input, list), '输入内容必须是列表'
# 下面的操作都是基于前提:input 必须是 list
if len(input) == 1:
...
elif len(input) == 2:
...
else:
...

循环结构

循环结构应用场景:

每个人的生活和工作都充满了循环,很多时候,循环意味着重复和枯燥:

比如你需要下载很多很多张图片,本来你是要手动操作的,而计算机通过【循环】,就可以依照某些规则,帮你一张一张地下载图片,你在一旁歇着就好。再比如作为运营,可能需要去解散很多的用户群,本来要一个一个手动点击,而计算机通过【循环】,就可以依照某些规则,帮人一个一个解散。

Python 中的【循环语句】,可以让计算机能够重复性地、自动地执行指令。

Python 中提供了常用的两种循环结构支持:

  • for … in(For 循环)
  • while …(while 循环)

for 循环

[1] >>>> for … in …

Python for 循环可以遍历任何序列或者可迭代(Iterable)的数据元素,如 列表、字符串、元组、字典、集合 等。其一般格式如下:

1
2
for <variable> in <sequence/Iterable>:
<statements>

例如循环访问列表中元素对象的实例:

1
2
3
4
5
6
7
8
>>> languages = ["C", "C++", "Perl", "Python"]
>>> for x in languages:
... print (x)
...
C
C++
Perl
Python

一个很形象的 for 循环结构工作流程图 >>>>

1
2
3
4
5
6
7
for i in [1,2,3,4,5]:
print(i)

# 有一群数字在排队办业务,也就是列表[1,2,3,4,5]
# 它们中的每一个被叫到号的时候(for i in),就轮流进去一个空房间办业务
# 每一个数字进去房间之后,计算机都会说:“编号为 x 的用户正在办理业务”,也就是 print(i)
# 然后计算机忠实的为每一个数字提供服务,并将用户服务编号 1,2,3,4,5 都打印在了屏幕上用以表示正被使用

是不很好理解?

事实上,循环结构就是从一个定义好的元素队列中不断取值,然后完成相应操作,依此类推(循环)的过程。


[2] >>>> for … in … else …

除了上述的结构外,for ... in 语句还可以和 else 联合使用(不常见),构成如下循环结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> languages = ["C", "C++", "Perl", "Python"]
>>> for x in languages:
... print(x)
... else:
... print("No elements!!!")
...
C
C++
Perl
Python
No elements!!!
>>> print("循环完毕")
循环完毕

如上,for 循环结束后给出结束信息,以标识循环部分结束。


[3] >>>> for 循环中的 range() 函数的使用

前面在讲解序列的时候,我们提到过 range 也是一种序列结构,事实上,借助它可以生成一个自定义的数字序列。故,如果需要通过 数字序列 实现循环时,还可以使用 Python 内置的 range()() 函数。例如:

1
2
3
4
5
6
7
8
9
# range(x) 会自动生成一个从 0 到 x-1 的整数序列:
>>> for index in range(5):
... print(index)
...
0
1
2
3
4

也可以使用 range() 来限定数字序列区间的取值范围,甚至是步长。如下:

1
2
3
4
5
6
7
8
9
# 生成从 0 到 9,步长为 2 的五个整数组成的序列:
>>> for index in range(0,10,2):
... print(index)
...
0
2
4
6
8

我们再来看看 len() && range() 的组合用法以通过序列索引遍历序列(常见用法),这是有时是很方便的:

1
2
3
4
5
6
7
>>> website = ["Google", "Baidu", "Opera"]
>>> for index in range(len(website)):
... print(index, website[index])
...
0 Google
1 Baidu
2 Opera

while 循环

[1] >>>> while

先来给出 while 循环的工作流程图:

while 循环表示:满足条件,就按照流程办事。

Python 中 while 语句的一般形式:

1
2
while 判断条件:
语句

循环实例(1~100求和):

1
2
3
4
5
6
7
8
9
>>> n = 100
>>> sum = 0
>>> counter = 1
>>> while counter <= n:
... sum += counter
... counter += 1
...
>>> print("The sum is :",sum)
The sum is : 5050

可见,对于 【1~100求和】,只要满足条件【counter <= 100】就累加求和。


[2] >>>> while … else …

for ... in 语句一样,while ... else 也可以和 else,配合使用:

1
2
3
4
5
6
7
8
9
10
11
12
>>> n = 100
>>> sum = 0
>>> counter = 1
>>> while counter <= n:
... sum += counter
... counter += 1
... else:
... print("n > 100")
...
n > 100
>>> print("The sum is :",sum)
The sum is : 5050

[3] >>>> while 死循环

没有终止条件,就会导致无限循环(死循环):

1
2
while True
learn() # Python 中没有 learn() 函数,但我们要终生学习

for…in or while…

考虑一下:这两种循环结构什么场景下都适用么??!

for 循环和 whlie 循环选择的最大的区别在于【循环的工作量是否确定】 >>>>

for 循环就像空房间依次办理业务,直到把【所有工作做完】才下班。但 while 循环就像哨卡放行,【满足条件就一直工作】,直到不满足条件就关闭哨卡。

所以说,当我们【工作量确定】的时候,我们就可以让 for 循环来完成重复性工作。反之,要【工作量不确定时】可以让 while 循环来工作:

1
2
3
4
5
6
7
8
# 适合用 for...in... 循环
for i in 'HelloWorld':
print(i)

# 适合用 while 循环(不知道第几次可以输入正确)
password = ''
while password != '816':
password = input('请尝试输入密码:')

注意,类似于分支结构,for…in 和 while… 循环结构也是支持嵌套的!!!


Break && Continue

当我们在循环任务中,由于达到我们的目的不想再继续循环执行下去时,可以借助 break && continue 来进行循环的中止:

[1] >>>> break:跳出当前循环

break 语句可以跳出 forwhile 的循环体。如果你从 forwhile 循环中终止,任何对应的循环 else 块将不执行。实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> Astr = "Google"
>>> flags = 5
>>> while flags > 0:
... print("Current number:",flags)
... for char in Astr:
... if char == "o":
... break
... print("Current char:",char)
... flags -= 1
...
Current number: 5
Current char: G
Current number: 4
Current char: G
Current number: 3
Current char: G
Current number: 2
Current char: G
Current number: 1
Current char: G

可以发现,当存在循环嵌套时,break 只能跳出当前循环体,而外部循环仍在进行。

[2] >>>> continue: 跳过当次循环

continue 语句被用来告诉 Python 解释器跳过当前循环块中的剩余语句,然后继续进行下一轮循环。

1
2
3
4
5
6
7
8
9
>>> flags = 5
>>> while flags >= 3:
... flags -= 1
... if flags == 3:
... continue
... print(flags)
...
4
2

注意,我们知道循环语句可以有 else 子句,它在穷尽列表( for 循环)或条件变为 false (while 循环)导致循环终止时被执行,但循环被 break 终止时会跳过 else 语句块 不执行。


了解了分支结构以及循环结构,来运用一下吧:

冒泡排序

冒泡排序是数据结构中的经典算法,算法的实现思想遵循以下几步:

  • 比较相邻的元素,如果第一个比第二个大,就交换它们两个;
  • 从最开始的第一对到结尾的最后一对,对每一对相邻元素做步骤 1 所描述的比较工作,并将最大的元素放在后面。这样,当从最开始的第一对到结尾的最后一对都执行完后,整个序列中的最后一个元素便是最大的数;
  • 将循环缩短,除去最后一个数(因为最后一个已经是最大的了),再重复步骤 2 的操作,得到倒数第二大的数;
  • 持续做步骤 3 的操作,每次将循环缩短一位,并得到本次循环中的最大数。直到循环个数缩短为 1,即没有任何一对数字需要比较,此时便得到了一个从小到大排序的序列。

例如,使用 for 循环实现用冒泡排序算法对 [5,8,4,1] 进行排序:

1
2
3
4
5
6
7
data = [5,8,4,1]
#实现冒泡排序
for i in range(len(data)-1):
for j in range(len(data)-i-1):
if(data[j]>data[j+1]):
data[j],data[j+1] = data[j+1],data[j]
print("排序后:",data)

运行结果如下:

1
排序后: [1, 4, 5, 8]

Python 中的推导式

推导式(又称解析器),是 Python 独有的一种特性。

前面在介绍列表、元组、字典以及集合等数据类型的创建时,都给出过使用推导式的创建方法,但只是简单提了一下。

事实上,使用推导式可以快速生成符合条件的列表、元组、字典以及集合类型的数据,因此推导式又可细分为 列表推导式元组推导式字典推导式 以及 集合推导式

推导式统一语法格式如下:

1
[{( 表达式 for 迭代变量 in 可迭代对象 [if 条件表达式] )}]

此格式中,具体使用那种括号视数据类型而定;且 [if 条件表达式] 不是必须的,用于进行元素过滤。


列表推导式

列表推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的列表。

列表推导式的语法格式如下:

1
[表达式 for 迭代变量 in 可迭代对象 [if 条件表达式] ]

初学者可以这样认为,它只是对 for 循环语句的格式做了一下简单的变形,并用 [] 括起来而已,只不过最大的不同之处在于,列表推导式最终会将循环过程中,表达式计算得到的一系列值组成一个列表。

例如如下代码(程序一):

1
2
3
4
5
6
7
a_range = range(10)
# 对a_range执行for表达式
a_list = [x * x for x in a_range]
# a_list集合包含10个元素
print(a_list)

# 输出:[0 , 1 , 4 , 9 , 16 , 25 , 36 , 49 , 64, 81]

还可以在列表推导式中添加 [if 条件语句],过滤符合条件的元素:

1
2
3
4
5
6
# 偶数
b_list = [x * x for x in a_range if x % 2 == 0]
# a_list集合包含5个元素
print(b_list)

# 输出:[0 ,4 , 16, 36, 64]

另外,以上所看到的列表推导式都只有一个循环,实际上它可使用多个循环,就像嵌套循环一样。例如如下代码:

1
2
3
4
5
6
7
src_a = [30, 12, 66, 34, 39, 78, 36, 57, 121]
src_b = [3, 5, 7, 11]
# 只要y能整除x,就将它们配对在一起
result = [(x, y) for x in src_b for y in src_a if y % x == 0]
print(result)

# 输出: [(3, 30), (3, 12), (3, 66), (3, 39), (3, 78), (3, 36), (3, 57), (5, 30), (11, 66), (11, 121)]

元组推导式

元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组。

元组推导式的语法格式如下:

1
(表达式 for 迭代变量 in 可迭代对象 [if 条件表达式] )

通过和列表推导式做对比,你会发现,除了元组推导式是用 () 圆括号将各部分括起来,而列表推导式用的是 [],其它完全相同。不仅如此,元组推导式和列表推导式的用法也完全相同。

例如,我们可以使用下面的代码生成一个包含数字 1~9 的元组:

1
2
a = (x for x in range(1,10))
print(a)

输出结果:

1
<generator object <genexpr> at 0x0000020BAD136620>

可以看出,使用元组推导式生成的结果并不是一个元组,而是一个生成器对象(后续会介绍),这一点和列表推导式是不同的。

如果我们想要使用元组推导式获得新元组或新元组中的元素,有以下三种方式:

1.使用 tuple() 函数,可以直接将生成器对象转换成元组,例如:

1
2
3
a = (x for x in range(1,10))
print(tuple(a))
# 运行结果为:(1, 2, 3, 4, 5, 6, 7, 8, 9)

2.直接使用 for 循环遍历生成器对象,可以获得各个元素,例如:

1
2
3
4
5
a = (x for x in range(1,10))
for i in a:
print(i,end=' ')
print(tuple(a))
# 运行结果:1 2 3 4 5 6 7 8 9 ()

3.使用 next() 方法遍历生成器对象,也可以获得各个元素,例如:

1
2
3
4
5
6
a = (x for x in range(3))
print(a.__next__())
print(a.__next__())
print(a.__next__())
a = tuple(a)
print("转换后的元组:",a)

运行结果为:

1
2
3
4
0
1
2
转换后的元组: ()

无论是使用 for 循环遍历生成器对象,还是使用 next() 方法遍历生成器对象,遍历后原生成器对象将不复存在,这就是遍历后转换原生成器对象却得到空元组的原因。


字典推导式

字典推导式可以借助列表、元组、字典、集合以及 range 区间,快速生成符合需求的字典。

字典推导式的语法格式如下:

1
{表达式 for 迭代变量 in 可迭代对象 [if 条件表达式]}

可以看到,和其它推导式的语法格式相比,唯一不同在于,字典推导式用的是大括号{}。

【例 1】

1
2
3
4
5
6
listdemo = ['C语言中文网','c.biancheng.net']
#将列表中各字符串值为键,各字符串的长度为值,组成键值对
newdict = {key:len(key) for key in listdemo}
print(newdict)

# Output: {'C语言中文网': 6, 'c.biancheng.net': 15}

【例 2】 交换现有字典中各键值对的键和值

1
2
3
4
5
olddict={'test': 6, 'test2': 15}
newdict = {v: k for k, v in olddict.items()}
print(newdict)

# Output: {6: 'test', 15: 'test2'}

【例 3】 使用 if 表达式筛选符合条件的键值对

1
2
3
4
5
olddict={'test': 6, 'test2': 15}
newdict = {v: k for k, v in olddict.items() if v>10}
print(newdict)

# Output: {15: 'test2'}

集合推导式

集合推导式可以借助列表、元组、字典、集合以及 range 区间,快速生成符合需求的集合。

集合推导式的语法格式如下:

1
{表达式 for 迭代变量 in 可迭代对象 [if 条件表达式]}

集合推导式和字典推导式的格式完全相同,那么给定一个类似的推导式,如何判断是哪种推导式呢?最简单直接的方式,就是根据表达式进行判断,如果表达式以键值对(key:value)的形式,则证明此推导式是字典推导式;反之,则是集合推导式。

【例 1】 既然生成的是集合,那么其保存的元素必须是唯一的

1
2
3
4
5
tupledemo = (1,1,2,3,4,5,6,6)
setnew = {x**2 for x in tupledemo if x%2==0}
print(setnew)

# Output: {16, 4, 36}

Author

Waldeinsamkeit

Posted on

2018-01-09

Updated on

2023-01-16

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.