《Python基础教程》第5章笔记:条件、循环及其他语句
《Python基础教程》第1章笔记👉https://blog.csdn.net/holeer/article/details/143052930
第5章 条件、循环及其他语句
你已见过几种语句,先来看看这些语句的其他一些用法,再深入探讨条件语句和循环语句。然后,我们将介绍列表推导,它们虽然是表达式,但工作原理几乎与条件语句和循环语句相同。最后,我们将介绍pass和exec。
5.1 再谈print和import
5.1.1 打印多个参数
你可以用print同时打印多个表达式,条件是用逗号分隔它们。在打印时,各表达式的值之间会有空格字符。如果需要,可用参数sep自定义分隔符,如print("I", "wish", sep="_")
。你还可自定义结束字符串,以替换默认的换行符,如print('Hello,', end='')
。
5.1.2 导入时重命名
# 从模块导入的4种方式
import somemodule
from somemodule import somefunction
from somemodule import somefunction, anotherfunction
from somemodule import *
# 仅当你确定要导入模块中的一切时,才使用最后一种方式。
# 可以用as指定别名
import math as foobar
from math import sqrt as foobar
5.2 赋值魔法
即便是不起眼的赋值语句也蕴藏着一些使用窍门。
5.2.1 序列解包
赋值语句你见过很多,有的给变量赋值,还有的给数据结构的一部分(如列表中的元素和切片,或者字典项)赋值,但还有其他类型的赋值语句。例如,可同时(并行)给多个变量赋值,如 x, y, z = 1, 2, 3
。你还可以用这种方法交换变量的值: x, y = y, x
。实际上,这里执行的操作称为序列解包(或可迭代对象解包):将一个序列(或任何可迭代对象)解包,并将得到的值存储到一系列变量中。
这对于处理元组型返回值很有用,比如 key, value = somedict.popitem()
。一般情况下,要解包的序列包含的元素个数必须与你在等号左边列出的目标个数相同。
# 可使用星号运算符(*)来收集多余的值,这样无需确保值和变量的个数相同
>>> a, b, *rest = [1, 2, 3, 4]
>>> rest
[3, 4]
>>> name = "Albus Percival Wulfric Brian Dumbledore"
>>> first, *middle, last = name.split()
>>> middle['Percival', 'Wulfric', 'Brian']
['Percival', 'Wulfric', 'Brian']
>>> a, *b, c = "abc"
>>> a, b, c
('a', ['b'], 'c')
# 带星号的变量最终包含的总是一个列表
5.2.3 增强赋值
对于表达式x = x + 1
,可以将右边表达式中的运算符(这里是+)移到赋值运算符(=)的前面,从而写成x += 1
。这称为增强赋值,适用于所有标准运算符,如*
、/
、%
等。增强赋值也可用于其他数据类型(只要使用的双目运算符可用于这些数据类型),如'foo' += 'bar'
、'foo' *= 2
。
5.3 代码块:缩进的乐趣
代码块是一组语句,可在满足条件时执行。它是通过缩进代码(即在前面加空格)来创建的。标准做法是只使用空格来缩进,且每级缩进4个空格。在同一个代码块中,各行代码的缩进量必须相同。在Python中,使用冒号(:)指出接下来是一个代码块,并将该代码块中的每行代码都缩进相同的程度。
5.4 条件和条件语句
5.4.1 这正是布尔值的用武之地
用作布尔表达式(如用作if语句中的条件)时,下面的值都将被解释器视为假:False None 0 "" () [] {}
。而其他各种值都被视为真,包括特殊值True。实际上,这种区别类似于“有些东西”和“没有东西”的区别。布尔值True和False属于类型bool,而bool()可以用来转换值,比如bool(42)
将会转换为True。
5.4.2 有条件地执行和if语句
if语句让你能够有条件地执行代码。这意味着如果条件(if和冒号之间的表达式)为前面定义的真,就执行后续代码块;如果条件为假,就不执行。
5.4.3 else子句
else子句不是独立的语句,而是if语句的一部分。当条件为假时执行else子句中的代码块。
Python还支持条件表达式——C语言中三目运算符的Python版本,如status = "friend" if name.endswith("Gumby") else "stranger"
。如果条件为真,表达式的结果为提供的第一个值,否则为第二个值。
5.4.4 elif子句
要检查多个条件,可使用elif。elif是else if的缩写,是包含条件的else子句。示例如下。
num = int(input('Enter a number: '))
if num > 0:
print('The number is positive')
elif num < 0:
print('The number is negative')
else:
print('The number is zero')
5.4.6 更复杂的条件
(1)比较运算符
表5-1 Python比较运算符(此处省略以下运算符的描述:< > <= >=
)
表达式 | 描述 |
---|---|
x == y | x等于y |
x != y | x不等于y |
x is y | x和y是同一个对象 |
x is not y | x和y是不同的对象 |
x in y | x是容器(如序列)y的成员 |
x not in y | x不是容器(如序列)y的成员 |
与赋值一样,Python也支持链式比较:可同时使用多个比较运算符,如0 < age <100
。
在对象比较上,==
用来检查两个对象是否相等,而is用来检查两个对象是否相同(是同一个对象)。警告:不要将is用于数和字符串等不可变的基本值。
字符串是根据其中字符的字母排列顺序进行大小比较的。实际上,比较的是字符的Unicode编码。因此,“B”<"a"
的结果为True。
大小比较还可用于列表,在比较时对逐个元素进行大小比较。比如, [1, 2] < [2, 1]
的结果为True。
(2)布尔运算符
运算符and(与)、or(或)、not(非)统称为布尔运算符。通过使用布尔运算符,能以任何方式组合真值。布尔运算符有个有趣的特征:只做必要的计算。例如,仅当x和y都为真时,表达式x andy才为真。因此如果x为假,这个表达式将立即返回假,而不关心y。这种行为称为短路逻辑。
5.4.7 断言
if语句有一个很有用的“亲戚”,其工作原理类似于:if not condition: crash program
,即让程序在错误条件出现时立即崩溃。如果你想要求某些条件得到满足,可在语句中使用关键字assert。还可在条件后面添加一个字符串,对断言做出说明。示例如下。
>>> age = -1
>>> assert 0 < age < 100
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AssertionError
>>> age = -1
>>> assert 0 < age < 100, 'The age must be realistic'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AssertionError: The age must be realistic
5.5 循环
5.5.1 while循环
while语句非常灵活,可用于在条件为真时反复执行代码块。比如:
x = 1
while x <= 100:
print(x)
x += 1
5.5.2 for循环
有时候你可能想根据需要进行定制循环,比如为序列(或其他可迭代对象)中每个元素执行代码块。为此,可使用for语句。比如:
words = ['how', 'are', 'you']
for word in words:
print(words)
for number in range(0,5):
print(number)
在以上代码中,range
是一个创建范围的函数。范围是一种列表,其左右索引与切片类似。range(5)、range(0,5)与[0,1,2,3,4]等效。
5.5.3 迭代字典
# 遍历字典的所有关键字
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(key, 'corresponds to', d[key])
for key, value in d.items():
print(key, 'corresponds to', value
5.5.4 一些迭代工具
Python提供了多个可帮助迭代序列(或其他可迭代对象)的函数,其中一些位于模块itertools
中,但还有一些内置函数使用起来也很方便。
#(1)并行迭代
# 有时候,你可能想同时迭代两个序列。比如:
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]
in range(len(names)):
print(names[i], 'is', ages[i], 'years old')
# 可以用zip将多个序列“缝合”起来,并返回一个由元组组成的序列。“缝合”后,可在循环中将元组解包。
for name, age in zip(names, ages):
print(name, 'is', age, 'years old')
#(2)迭代时获取索引
# 以下是一个在字符串集合中批量替换的示例。
for index, string in enumerate(strings):
if 'xxx' in string:
strings[index] = '[censored]'
5.5.5 循环控制
(1)break:用于结束(跳出)循环。某些循环不需要开始条件,但是需要结束条件,这样的循环通常用while True/break的组合实现。在循环体下面你还可以添加一个else子句,其中的代码仅在没有调用break跳出循环时才执行。
(2)continue:它结束当前迭代,并跳到下一次迭代开头。
5.6 简单推导
列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导。列表推导的工作原理非常简单,有点类似于for循环。示例如下。
>>> [x * x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [x * x for x in range(10) if x % 3 == 0]
[0, 9, 36, 81]
推导功能强大,但在很多情况下,使用普通循环和条件语句也可完成任务,且代码的可读性可能更高。
5.7 其他语句
5.7.1 什么都不做
在Python中代码块不能为空。如果还没确定代码块的内容,可以将pass语句用作占位符,它什么都不做。
5.7.3 使用exec和eval执行字符串及计算其结果
有时候,你可能想动态地编写Python代码,并将其作为语句进行执行,或作为表达式进行计算。这可能犹如黑暗魔法,一定要小心。
(1)函数exec将字符串作为代码执行。在调用它时,除了提供字符串参数之外,还应向它传递一个字典作为命名空间,用于放置变量,否则代码将污染你的命名空间。
>>> exec("print('Hello, world!')")
Hello, world!
>>> from math import sqrt
>>> exec("sqrt = 1")
>>> sqrt(4)
Traceback (most recent call last):
File "<pyshell#18>", line 1, in ?
sqrt(4)
TypeError: object is not callable: 1
>>> from math import sqrt
>>> scope = {}
>>> exec('sqrt = 1', scope)
>>> sqrt(4)
2.0
>>> scope['sqrt']
1
(2)函数eval计算用字符串表示的Python表达式的值,并返回结果。例如,你可使用如下代码来创建一个Python计算器:
>>> eval(input("Enter an arithmetic expression: "))
Enter an arithmetic expression: 6 + 18 * 2
42
与exec一样,也可向eval提供一个命名空间,虽然表达式通常不会像语句那样给变量重新赋值。(警告:通常不会不代表不能,比如,在表达式中可能调用给全局变量重新赋值的函数。因此,将eval用于不可信任的代码并不比使用exec安全。)