Python 流程控制 超全解析(不可错过)

时间:2020-12-20 20:36:22

流程控制

程序执行结构流程

 计算机程序在解决某个具体问题时,包括三种情形,即顺序执行所有的语句、选择执行部分的语句和循环执行部分语句,这正好对应着程序设计中的三种程序执行结构流程:顺序结构选择结构循环结构

  事实证明,任何一个能用计算机解决的问题,只要应用这三种基本结构来写出的程序都能解决。Python语言当然也具有这三种基本结构。

Python 流程控制 超全解析(不可错过)

程序执行结构

  • 顺承结构的程序特点是依照次序将代码一个一个地执行,并返回相应的结果,这种结构较为简单,易于理解;
  • 分支结构的程序多出了条件判断,即满足某种条件就继续执行,否则跳转到另外的条件上进行执行;
  • 循环结构用于处理可以迭代的对象,这种结构通过循环可迭代的对象,然后对每一个对象执行程序并产生结果。在迭代次数较多的情况下,使用顺承结构往往要写非常长的代码,而循环结构则非常简单。

补充(Python的缩进规则):

补充说明下

  Python的一大特色,强制缩进,目的是为了让程序知道,每段代码依赖哪个条件,如果不通过缩进来区分,程序怎么会知道,当你的条件成立后,去执行哪些代码呢?

  在其它的语言里,大多通过{}来确定代码块,比如C,C++,Java,Javascript都是这样。但Python比较独树一帜,依靠强制缩进来区分代码块,这也是Python简洁的地方,所以我们要多加注意。

  Python的缩进有以下几个原则:

  • *代码必须顶行写,即如果一行代码本身不依赖于任何条件,那它必须不能进行任何缩进
  • 同一级别的代码,缩进必须一致
  • 官方建议缩进用4个空格

顺承结构

1.1 定义

现在创建一个列表a:

a = [1,2,3,4,5]

需要打印列表a中的所有元素,可以有如下写法,虽然烦琐但完成了任务。这种顺序执行的编程结构就是顺承结构:

print(a[0])

print(a[1])

print(a[2])

print(a[3])

print(a[4])

1

2

3

4

5

1.2 逻辑行与物理行

Python中,代码是逐行提交给解释器进行编译的,这里的一行称为逻辑行,实际代码也确实是一行,那么代码的物理行就只有一行,例如上述print代码,逻辑行和物理行是统一的。

但某些情况下,编写者写入一个逻辑行的代码过长时,可以分拆为多个物理行执行,例如:

tuple(set(list([1,2,3,4,5,6,7,8])))

(1, 2, 3, 4, 5, 6, 7, 8)

可以写为如下方式,符号 ’ ’ 是换行的标识,此时代码还是一个逻辑行,但有两个物理行。

tuple(set(list([1,2,3,

 4,5,6,7,8])))

(1, 2, 3, 4, 5, 6, 7, 8)

当多个逻辑行代码过短时:

x = 1

y = 2

z = 3

print(x,y,z)

(1, 2, 3)

可以使用分号“;”将多个逻辑行转化为一个物理行执行:

x = 1;y = 2;z = 3;print(x,y,z)

(1, 2, 3)

选择结构(if判断)

定义

分支结构的分支用于进行条件判断

1.1 if (单分支)

学什么都是为了让计算机向人一样工作,我们无时无刻都在判断。路边路过一个生物,你会判断两个人是不是会表白?首先会判断这个生物是不是人类,并且这个人类是个女人,年龄大于18小于20几岁。你首先需要记录一堆数据,然后才会用你的大脑去判断。if表示if成立代码成立会干什么。

if 条件:
代码1
代码2
代码3
...
# 代码块(同一缩进级别的代码,例如代码1、代码2和代码3是相同缩进的代码,这三个代码组合在一起就是一个代码块,相同缩进的代码会自上而下的运行)
cls = 'human'
gender = 'female'
age = 18 if cls == 'human' and gender == 'female' and age > 16 and age < 22:
print('开始表白') print('end...')
开始表白
end...

1.2 if...else (双分支)

if 条件:
代码1
代码2
代码3
...
else:
代码1
代码2
代码3
...

if...else表示if成立代码成立会干什么,else不成立会干什么。

cls = 'human'
gender = 'female'
age = 38 if cls == 'human' and gender == 'female' and age > 16 and age < 22:
print('开始表白')
else:
print('阿姨好')
阿姨好

1.3 if...elif...else(多分支)

if 条件1:
代码1
代码2
代码3
...
elif 条件2:
代码1
代码2
代码3
...
elif 条件3:
代码1
代码2
代码3
...
...
else:
代码1
代码2
代码3
...

if...elif...else表示if条件1成立干什么,elif条件2成立干什么,elif条件3成立干什么,elif...否则干什么。

cls = 'human'
gender = 'female'
age = 28 if cls == 'human' and gender == 'female' and age > 16 and age < 22:
print('开始表白')
elif cls == 'human' and gender == 'female' and age > 22 and age < 30:
print('考虑下')
else:
print('阿姨好')
考虑下

1.4if的嵌套

如果我们表白的时候,表白成功的时候我们是不是会做什么,表白不成功是不是又会会做什么呢?

# if的嵌套
cls = 'human'
gender = 'female'
age = 18
is_success = False if cls == 'human' and gender == 'female' and age > 16 and age < 22:
print('开始表白')
if is_success:
print('那我们一起走吧...')
else:
print('我逗你玩呢')
else:
print('阿姨好')
开始表白
我逗你玩呢

循环结构(while循环和for循环)

定义

这里介绍Python中的for循环结构和while循环结构,循环语句用于遍历枚举一个可迭代对象的所有取值或其元素,每一个被遍历到的取值或元素执行指定的程序并输出。这里可迭代对象指可以被遍历的对象,比如列表、元组、字典等

while循环

结构:

while<条件>:

	<语句1>

注意:与for循环不同的是,while语句只有在测试条件为假时才会停止。

(Python独有):     

while<条件>:

	<语句1>

else:

	<语句2> 
注意:while 后面的else 作用是指,当while 循环正常执行完,中间没有被break 中止的话,就会执行else后面的语句。 (死循环): while True: <语句> 注意:while 是只要后边条件成立(也就是条件结果为真)就一直执行。

for循环

Python语言中的for语句与其他高级程序设计语言有很大的不同,其他高级语言for语句要用循环控制变量 来控制循环。Python中for语句是通过循环遍历某一序列对象(字符串、列表、元组等)来构建循环,循环结束的条件就是对象被遍历完成。

结构:

for <循环变量> in <循环对象>:

	<语句1>
break
else: <语句2>

for语句的循环对象可以是列表、元组以及字符串,可以通过range()函数产生一个迭代值,以完成计数循环。range( start, stop , step),step表示步长。   

   for语句使用range()函数可以构建基于已知循环次数的循环程序,也可以以range()生成的数字作为索引来访问列表、元组、字符串中的值。

   需要注意的是,range() 函数返回的对象表现为它是一个列表,但事实上它并不是,range()函数并不是在调用时一次生成整个序列,而是遍历一次才产生一个值,以减少内存的占用,其本质是一个迭代器。

循环中止语句

  如果在循环的过程中,因为某些原因,你不想继续循环了,怎么把它中止掉呢?这就用到break 或 continue 语句。

  • continue语句是从 C 中借鉴来的,它表示循环继续执行下一次迭代
  • break 语句和 C 中的类似,用于跳出最近的一级 for或 while 循环。

  break 和continue的作用和区别:

  • break用于完全结束一个循环,跳出循环体执行循环后面的语句。
  • continue和break有点类似,区别在于continue只是终止本次循环,接着还执行后面的循环,break则完全终止循环。

例如:break

count = 0
while count <= 100 : #只要count<=100就不断执行下面的代码
print("loop ", count)
if count == 5:
break
count +=1 #每执行一次,就把count+1,要不然就变成死循环啦,因为count一直是0

再看例如:continue  

count = 0
while count <= 100 :
count += 1
if count > 5 and count < 95: #只要count在6-94之间,就不走下面的print语句,直接进入下一次loop
continue
print("loop ", count)

补充

循环技巧

在字典中循环时,关键字和对应的值可以使用 items() 方法同时解读出来:

>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
... print(k, v)
...
gallahad the pure
robin the brave

在序列中循环时,索引位置和对应值可以使用 enumerate() 函数同时得到:

>>> for i, v in enumerate(['tic', 'tac', 'toe']):
... print(i, v)
...
0 tic
1 tac
2 toe

同时循环两个或更多的序列,可以使用 zip() 整体打包:

>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
... print('What is your {0}? It is {1}.'.format(q, a))
...
What is your name? It is lancelot.
What is your quest? It is the holy grail.
What is your favorite color? It is blue.

需要逆向循环序列的话,先正向定位序列,然后调用 reversed()函数:

>>> for i in reversed(range(1, 10, 2)):
... print(i)
...
9
7
5
3
1

要按排序后的顺序循环序列的话,使用 sorted() 函数,它不改动原序列,而是生成一个新的已排序的序列:

>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
... print(f)
...
apple
banana
orange
pear

若要在循环内部修改正在遍历的序列(例如复制某些元素),建议您首先制作副本。在序列上循环不会隐式地创建副本。切片表示法使这尤其方便:

>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]: # Loop over a slice copy of the entire list.
... if len(w) > 6:
... words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

range() 函数

如果你需要一个数值序列,内置函数 [range()会很方便,它生成一个等差级数链表:

>>> for i in range(5):
... print(i)
...
0
1
2
3
4

range(10) 生成了一个包含 10 个值的链表,它用链表的索引值填充了这个长度为 10 的列表,所生成的链表中不包括范围中的结束值。也可以让 range()操作从另一个数值开始,或者可以指定一个不同的步进值(甚至是负数,有时这也被称为 “步长”):

range(5, 10)
5 through 9 range(0, 10, 3)
0, 3, 6, 9 range(-10, -100, -30)
-10, -40, -70

需要迭代链表索引的话,如下所示结合使 用 range() 和 len()

>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a)):
... print(i, a[i])
...
0 Mary
1 had
2 a
3 little
4 lamb

不过,这种场合可以方便的使用 enumerate()

如果你只是打印一个序列的话会发生奇怪的事情:

>>> print(range(10))
range(0, 10)

在不同方面 range() 函数返回的对象表现为它是一个列表,但事实上它并不是。当你迭代它时,它是一个能够像期望的序列返回连续项的对象;但为了节省空间,它并不真正构造列表。

我们称此类对象是 可迭代的,即适合作为那些期望从某些东西中获得连续项直到结束的函数或结构的一个目标(参数)。我们已经见过的 for语句就是这样一个迭代器。list() 函数是另外一个( 迭代器 ),它从可迭代(对象)中创建列表:

>>> list(range(5))
[0, 1, 2, 3, 4]

我们会看到更多返回可迭代(对象)和以可迭代(对象)作为参数的函数。

enumerate(iterablestart = 0 )函数

返回一个枚举对象。iterable必须是序列, 迭代器或其他支持迭代的对象。__next__()enumerate()返回的迭代器的方法 返回一个元组,该元组包含一个计数(从start开始,默认为0),以及通过对iterable进行迭代而获得的值。

>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

相当于:

def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1

zip(** iterables* )函数

创建一个迭代器,以聚合每个可迭代对象中的元素。

返回一个元组的迭代器,其中第i个元组包含每个参数序列或可迭代对象中的第i个元素。当最短的可迭代输入耗尽时,迭代器将停止。使用单个可迭代参数,它将返回1元组的迭代器。没有参数,它将返回一个空的迭代器。相当于:

def zip(*iterables):
# zip('ABCD', 'xy') --> Ax By
sentinel = object()
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
elem = next(it, sentinel)
if elem is sentinel:
return
result.append(elem)
yield tuple(result)

保证了可迭代对象的从左到右的评估顺序。这使得使用可以将数据系列聚类为n个长度的组成为一个习惯用法zip(*[iter(s)]*n)。这将重复相同的迭代器n时间,以便每个输出元组都具有n对迭代器的调用结果。这具有将输入分成n个长度的块的效果。

zip()仅当您不关心较长的可迭代对象的尾随,不匹配的值时,才应将其与不等长的输入一起使用。如果这些值很重要,请itertools.zip_longest()改用。

zip()*运算符结合使用可以解压缩列表:

>>>

>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> zipped = zip(x, y)
>>> list(zipped)
[(1, 4), (2, 5), (3, 6)]
>>> x2, y2 = zip(*zip(x, y))
>>> x == list(x2) and y == list(y2)
True

reversedseq )函数

返回一个反向迭代器。 seq必须是具有__reversed__()方法或支持序列协议的对象(该 __len__()方法和__getitem__()带有整数参数的方法始于0)。

sortediterablekey = Nonereverse = False* )函数

iterable中的项目返回一个新的排序列表。

有两个可选参数,必须将其指定为关键字参数。

key指定一个参数的功能,该参数用于从iterable中的每个元素中提取一个比较键(例如key=str.lower)。默认值为None(直接比较元素)。

reverse是一个布尔值。如果设置为True,则对列表元素进行排序,就好像每个比较都被反转一样。

用functools.cmp_to_key()一个老式的转换CMP功能的 关键功能。

内置sorted()]功能保证稳定。如果可以保证不更改比较相等的元素的相对顺序,则排序是稳定的-这有助于多次通过排序(例如,按部门排序,然后按薪级等级排序)。

有关排序示例和简短的排序教程,请参阅《如何排序》