Python基础教程3--条件和循环
本文主要介绍Python的条件、循环语句相关知识,通过条件和循环,我们就可以编写程序逻辑。
赋值魔法
最简单的的赋值操作,也有一些特殊的技巧
- 序列解包/递归解包: 将多个值的序列解开,然后放到变量的序列中,从而一次进行多个赋值操作,更形象点表示如下:
>>> values = 1, 2, 3 >>> values (1, 2, 3) >>> x, y, z = values >>> x 1 >>> z 3
可以简写成
>>> x, y, z = 1, 2, 3 >>> x 1 >>> z 3
可以简化交换两个变量的操作(不需要中间变量)
>>> x = 1 >>> y = 2 >>> x, y = y, x # 变量交换 >>> x 2 >>> y 1
当函数/方法返回元组时,这个特性非常有用,通过一个赋值语句就可以很容易的对返回的值进行访问。
>>> ph_dict = {'zht': '10000', 'lz': '10086'} >>> key, value = ph_dict.popitem() >>> key 'lz' >>> value '10086'
请注意,解包的序列中的元素数量必须要和放置在赋值符号(=)左边的变量数量完全一致,否则会引发异常
>>> x, y, z = 1, 2 # 数量不一致,引发异常 ValueError: not enough values to unpack (expected 3, got 2) >>> x, y = 1, 2, 3 ValueError: too many values to unpack (expected 2)
还有一个解包特性就是,可以像函数的位置参数列表一样,使用星号(*),将其余参数收集到一个变量中
>>> x, y, *rest = 1, 2, 3, 4, 5, 6 # 在x和y被赋值以后,将其它参数都收集到rest列表中 >>> x 1 >>> y 2 >>> rest # 其它参数列表 [3, 4, 5, 6]
其中星号变量可以放在开头或中间的位置
>>> *rest, y, z = 1, 2, 3, 4, 5, 6 # 第一个位置 >>> rest [1, 2, 3, 4] >>> x, *rest, y = 1, 2, 3, 4, 5, 6 # 中间位置 >>> rest [2, 3, 4, 5]
- 链式赋值: 是将同一个值赋给多个变量的捷径操作,从右向左对变量进行逐个赋值。
>>> x = y = func()
与以下语句效果一样(从右向左赋值)
>>> y = func() >>> x = y
请注意,链式赋值和以下语句不一定等价
>>> y = func() # 如果func返回当前时间,两次返回的时间会不一致 >>> x = func()
- 增量赋值: 将运算符(+-*/%)放在赋值运算符=的左边的写法
>>> x = 2 >>> x += 1 # 等价于x = x + 1 >>> x 3 >>> x *= 2 # 等价于x = x * 2 >>> x 6 >>> str1 = 'java' # 对于其他类型也试用 >>> str1 += 'script' >>> str1 'javascript' >>> str1 *= 2 >>> str1 'javascriptjavascript'
语句块
语句块是条件为真(条件语句)或者执行多次(循环语句)时执行的一组语句。
- Python通过冒号(:)标识语句块的开始
- 通过在代码前放置空格的方式来创建语句块,同一块中的每行都应该有相同的缩进。
- 当回退到和已经闭合的块一样的缩进时,就表示当前块已经结束。
- Python不允许空的语句块,如果只是想加一个占位符,后续再实现相关逻辑,可以使用pass语句。
请注意,不同的缩进代表不同的语句块,在编码过程中很可能会出现因为缩进导致的逻辑问题。
下面是一个语句块示例
score = int(input('What is your score?'))
if score >= 60: # 块1开始
if score >= 90: # 块1-1开始
print('excellent') # 块1-1结束
elif score >= 80: # 块1-2开始
print('good') # 块1-2结束
else: # 块1-3开始
print('pass') # 块1-3结束
# 块1结束
else: # 块2开始
print('fail') # 块2结束
到目前为止,讲到的程序示例都是一条一条顺序执行的,接下来介绍让程序选择是否执行或者选择执行多次。
条件
布尔值和条件真假
讲条件语法之前,我们先看下什么是条件,既然是条件,就分真值和假值。
标准的布尔值只有True和False两个,而我们这里讲的条件,除了标准布尔值,还有其他值也可以被解释成真值和假值。
以下值作为条件时,会被解释器看作假值:
False None 0 '' () {} []
请注意,这几个值,在条件中使用都表示假值,但是这几个值相互之间都不相等,None == 0 结果为 False。
其他值在条件中都会被解释成真值,也可以把真值和假值理解为:"有些东西"和"没有东西"。
>>> bool(1)
True
>>> bool(0)
False
>>> bool('')
False
>>> bool('hello')
True
因为所有值都可以用作布尔值,所以几乎不需要进行显示转换,Python会自动转换。
比较运算符
除了一般的真假值,用在条件中最基本的运算符就是比较运算符了,它们用来比较其他对象,并返回True/False,比较运算符如下表所示
表达式 | 描述 | 注意项 |
---|---|---|
x == y | x等于y | 两个值相等,并不代表是同一个值,比如x=[1,2],y=[1,2],虽然x==y为True,但是x并不是y,请参考x is y。 |
x != y | x不等于y | 同上 |
x < y | x小于y | 除了数字,像字符串,列表都可以进行比较,比如'a'<'b'为True,[1,2]>[2,1]为False |
x > y | x大于y | 同上 |
x >= y | x大于等于y | 同上 |
x <= y | x小于等于y | 同上 |
x is y | x和y是同一对象 | 请注意,is是判定同一性而不是相等性,例如x=[1,2],y=[1,2],虽然x==y为True,但是x和y并不是同一个对象, 对于简单数据类型(数字/字符串/布尔/None),如果两个值相等则表示同一对象,如果x='a',y='a',x is y为True 对于复杂数据类型(列表/元组/字典/集合/对象),只有指向同一内存地址引用才是True |
x is not y | x和y是不同的对象 | 同上 |
x in y | x是y容器的成员 | 请参考序列 |
x not in y | x不是y容器的成员 | 同上 |
比较运算和赋值一样,几个运算符是可以连接在一起使用的,比如 60< score <=80
布尔运算符和三元运算符
以上布尔值和比较运算符都是一个条件,但我们经常会遇到需要检查多个条件的情况,比如,检查用户输入的数字是否位于1-10之间,一个方法是可以通过嵌套if/else实现
num = int(input('Enter a number between 1 and 10: '))
if num > 0:
if num <= 10:
print('Great!')
else:
print('Wrong!')
else:
print('Wrong!')
虽然以上方法没问题,但是方法略显笨拙,需要打印两次Wrong,有一种简洁的实现方法如下
num = int(input('Enter a number between 1 and 10: '))
if num > 0 and num <= 10:
print('Great!')
else:
print('Wrong!')
上例中使用到的and运算符就是所谓的布尔运算符(又称逻辑运算符),一共有三个布尔运算符and,or和not,它们可用于连接两个布尔值。
- and: 只有当两者都为真时,结果才会真,否则结果为假
- or: 两者只要有一个为真,则结果为真,否则结果为假
- not: 取反操作
而且,这三个布尔运算符可以随意结合使用
if((cash > price) or customer_has_good_credit) and not out_of_stock:
give_goods()
请注意,and和or运算符采用的是惰性求值或称为短路逻辑模式,只有在需要求值时才进行求值。
举个例子,表达式x and y,如果x为假,表达式就会立即返回False,而不管y的值,如果y是一个函数,也不会被执行,就像被"短路"了一样。
这种短路逻辑可以用来实现其它编程语言中经常用到的三元运算符, result = condition_true_result if condition else condition_false_result。
>>> name = 'Python'
>>> greeting = 'Hello ' + (name if name !='' else 'stranger')
>>> greeting
'Hello Python'
>>> name = ''
>>> greeting = 'Hello ' + (name if name !='' else 'stranger')
>>> greeting
'Hello stranger'
条件执行和if/else/elif语句
前面我们讲了条件和真假值,通过if语句,就可以实现条件执行,如果条件为真,那么后面的语句块就会被执行,如果条件为假,则语句块就不会被执行。
也可以用else子句增加一种选择,如果if后面的语句块没有被执行,就会执行else中的子句。
如果要检查多个子句,就可以用elif,它表示else if的意思。
我们通过一个示例,演示下if/else/elif的使用
score = int(input('What is your score?'))
if score >= 60: # 如果>=60,执行下面的语句块
if score >= 90: # 代码块嵌套,如果>=90,结果为:excellent
print('excellent')
elif score >= 80: # 如果不>=90,但>=80,结果为:good
print('good')
else: # 如果既不>=90,又不>=80,结果为:pass
print('pass')
else: # 如果<60,执行下面的语句块
print('fail')
循环
循环就是一直重复执行,直到人为停止,比如要循环打印从1-100的所有数字,通过循环语句就可以方便快捷的实现,而不用写100次的print语句。
循环主要有两种,while循环和for循环。
while循环
while语句非常灵活,可以用来在任何条件为真的情况下,重复执行一个代码块。
上述依次打印1-100数字的例子,通过while循环可以像下面这样实现
x = 1
while x <= 100: # 一直循环,直到x>100结束
print(x)
x += 1
for循环
主要用于迭代一个集合(列表/字典)中的每一个元素,并执行一个代码块。
numbers = [11, 22, 33, 44, 55, 66]
for item in numbers:
print(item)
#依次打印出numbers中的值,11,22……
遍历列表和字典
以下是程序中经常用到的遍历列表和字典的方法
- 遍历列表
- 简单遍历
numbers = [11, 22, 33, 44, 55, 66] for item in numbers: print(item) #依次打印出11/22/33/44/55/66
- 带索引的遍历
如果既想遍历序列中的对象,同时还要获取当前对象的索引,可以通过内建的enumerate函数实现
numbers = [11, 22, 33, 44, 55, 66] for item in enumerate(numbers): # item是一个索引和值组成的元组 (0, 11)/(1, 22)/…… print('index:',item[0],'value:',item[1]) #依次打印出: index: 0 value: 11/index: 1 value: 22/
当然通过赋值魔法,可以直接使用索引和对象
numbers = [1, 2, 3, 4, 5, 6] for index, value in enumerate(numbers): # 解包赋值 print('index:', index, 'value:', value)
- 并行遍历
程序可以通过内置的zip函数同时迭代两个序列,
names = ['Lucy', 'Ryder', 'Tom'] ages = [18, 7, 20] for name, age in zip(names, ages): print(name, ' is ', age) #依次打印出: Lucy is 18/Ryder is 7/Tom is 20
- 简单遍历
- 遍历字典
- 遍历key
d = {'x': 1, 'y': 2, 'z': 3} for key in d: print(key, ":", d[key]) #打印出x : 1/y : 2/z : 3
- 遍历key和value
还可以通过字典的items方法,将键值作为元组返回再遍历
d = {'x': 1, 'y': 2, 'z': 3} for key, value in d.items(): print(key, ":", value)
- 遍历key
跳出循环
一般来说循环会一直执行到条件为假或者序列元素迭代用完时,但是有时候可能想要提前结束循环,或者中断当前循环,进行新的一轮迭代。
- break: 用于结束(跳出)循环。
举个简单例子,遍历一个数字列表,如果有值>100,则结束遍历
numbers = [60, 20, 130, 10] for item in numbers: if item > 100: break print(item) #打印出 60,20后停止遍历,不会继续打印其它值
break经常和while True结合使用,while True实现了了一个永远不会自己停止的循环,结合if和break,可以在满足某项条件时,终止循环。
比如一个程序接收用户输入,并打印,直到用户输入了'bye',则终止程序运行
while True: word = input("Please enter a word: ") if word == 'bye': break print("The word is ", word) #运行结果如下: #Please enter a word: hello #The word is hello #Please enter a word: hi #The word is hi #Please enter a word: bye #Process finished with exit code 0 #退出
- continue: 用于结束当前循环,跳到下一轮循环的开始,它跳过剩余的循环体,但是不结束循环。
比如要打印出数字列表中的偶数,如果是奇数则跳过
numbers = [1, 2, 3, 4, 5, 6] for item in numbers: if item % 2 != 0: continue # 跳到下一个循环,而不是退出 print(item) #运行结果如下: #2 #4 #6
循环中的else子句
当使用break跳出循环时,通常是因为找到了某个对象或者某个事件发生了。
在跳出前做一些事情很简单,但是有时想在没有跳出(比如没有发现某个对象)时做些事情,这时就可以使用else子句,它仅在没有调用break时执行。
numbers = [1, 2, 3, 4, 5, 6]
for item in numbers:
if item > 100:
break
print(item)
else:
print("It's ok") # 当所有值都<=100时,不会触发break,此时else中的子句会执行。
可以结合else子句和break/continue跳出嵌套循环
for x in range(10):
for y in range(10):
print(x * y)
if x * y > 50:
break
else:
continue # y层循环没有break时调用,执行continue,会直接进入下一个x循环,不会执行下一行的break语句
break # y层循环break时,上一行的continue语句不会被调用,会执行当前break跳出x层循环
列表推导式
列表推导式是利用其它列表创建新列表的一种方法,工作方式类似于for循环。
它的语法是: x_about_value for x in alist if condition,x_about_value是通过x元素生成的值,if condition可以省略。
意思是对于alist的每个元素x,如果符合某个条件(如果省略表示都符合),则将生成的值x_about_value放到新列表中,遍历结束返回新列表。
以下代码创建一个1-9的平方组成的列表
>>> [x*x for x in range(10)] # range是内置函数,返回一个指定起止值的可迭代序列
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
也可以嵌套更多的for语句
>>> [(x, y) for x in range(3) for y in range(2)] # 可以嵌套更多的for语句
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]