当前位置: 首页 > news >正文

Python教程(二)——控制流工具前半部分

目录

  • 1. if语句
  • 2. for语句
  • 3. range()函数
  • 4. break和continue语句
  • 5. 循环的else子句(有点抽象)
  • 6. pass语句
  • 7. match语句
  • 参考

1. if语句

  最让人耳熟能详的语句应当是if语句:

>>> x = int(input('Please enter an integer: '))
Please enter an integer: 42
>>> if x < 0:
··· 	x = 0
···		print('Negative changed to zero')
··· elif x == 0:
···		print('Zero')
··· elif x == 1:
···		print('Single')
··· else:
···		print('More')
···
More

  可有零个或多个elif部分,else部分也是可选的。关键字elif是else if的缩写,用于避免过多的缩进。if…elif…elif…序列可以当作其它语言中switch或case语句的替代品。
  如果是把一个值与多个常量进行比较,或者检查特定类型或属性,match语句更有用。

2. for语句

  Python的for语句与C或Pascal中的不同。Python的for语句不迭代算术递增数值,或是给予用户定义迭代步骤和结束条件的能力,而是在列表或字符串等任意序列的元素上迭代,按它们在序列中出现的顺序。例如:

>>> # 度量一些字符串
>>> words = [ 'cat', 'window', 'defenestrate' ]
>>> for w in words:
··· 	print(w, len(w))
···
cat 3
window 6
defenestrate 12

  很难正确地在迭代多项集的同时修改多项集的内容。更简单的方法是迭代多项集的副本或者创建新的多项集:

# 创建实例多项集
users = { 'Hans': 'active', 'Eleonore': 'inactive', '景太郎': 'active' }# 策略:迭代一个副本
for user, status in users.copy().items():if status == 'inactive':del users[user]# 策略:创建一个新多项集
active_users = {}
for user, status in users.items():if status == 'active':active_users[user] = status

3. range()函数

  内置函数range()用于生成等差数列:

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

  生成的序列绝不会包含给定的终止值,range(10)生成10个值——长度为10的序列的所有合法索引。range可以不从0开始,且可以按给定的步长递增:

>>> list(range(5, 10))
[5, 6, 7, 8, 9]
>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(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

  如果直接打印一个range会发生意想不到的事情:

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

  range()返回的对象在很多方面和列表的行为一样,但其实它和列表不一样。该对象只有在被迭代时才一个一个地返回所期望的列表项,并没有真正生成过一个含有全部项的列表,从而节省了空间。
  这种对象称为可迭代对象,适合作为需要获取一系列值的函数或程序构件的参数。for语句就是这样的程序构件;以可迭代对象作为参数的函数例如sum():

>>> sum(range(4)) # 0 + 1 + 2 + 3
6

4. break和continue语句

  break语句将跳出最近的一层for或while循环:

>>> for n in range(2, 10):
···		for x in range(2, n):
···			if n % x == 0:
···				print(f"{n} equals {x} * {n // x}")
···				break
···
4 equals 2 * 2
6 equals 2 * 3
8 equals 2 * 4
9 equals 3 * 3

  continue语句将继续执行循环的下一次迭代:

>>> for num in range(2, 10)
··· 	if num % 2 == 0:
···			print(f"Found an even number {num}")
···			continue
···		print(f"Found an odd number {num}")
···
Found an even number 2
Found an odd number 3
Found an even number 4
Found an odd number 5
Found an even number 6
Found an odd number 7
Found an even number 8
Found an odd number 9

5. 循环的else子句(有点抽象)

  在for或while循环中break语句可能对应一个else子句。如果循环在未执行break的情况下结束,else子句将会执行。
  在for循环中,else子句会在循环结束其他最后一次迭代之后,即未执行break的情况下被执行。
  在while循环中,它会在循环条件变为假肢后执行。
  在这两类循环中,当在循环被break终结时else子句不会被执行。当然,其他提前结束循环的方式,如return或是引发异常,也会跳过else子句的执行。
  下面的搜索质数的for循环就是一个例子:

>>> for n in range(2, 10):
···		for x in range(2, n):
···			if n % x == 0:
···				print(n, 'equals', x, '*', n // x)
···				break
···		else:
···			# 循环到底未找到一个因数
···			print(n, 'is a prime number')
···
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

  分析else子句的一种方式是想象它对应于循环内的if。当循环执行时,它将运行一系列的if/if/if/else。if位于循环内部,会出现多次。当出现条件为真的。if位于循环内部,会出现多次。当出现条件为真的情况时,将发生break。如果条件一直不为真,则循环外的else子句将被执行。
  当配合循环使用时,else子句更像是try语句的else子句而不像if语句的相应子句:一个try语句的else子句在未发生异常时运行,而一个循环的else子句会在未发生break时运行。

6. pass语句

  pass语句不执行任何动作。语法上需要一个语句,但程序毋需执行任何动作时,可以使用该语句。例如:

>>> while True:
···		pass # 无限等待键盘中断Crtl+C
···

  这常用于创建一个最小的类:

>>> class MyEmptyClass:
···		pass
···

  pass还可用作函数或条件语句的占位符,让你保持在更抽象的层次进行思考。pass会被默默地忽略:

>>> def initlog(*args):
···		pass # 记得实现这个!
···

7. match语句

  match语句接受一个表达式并把它的值与一个或多个case块给出的一系列模式进行比较。这表面上像C、Java或JavaScript中的switch语句,但其实它更像Rust或Haskell中的模式匹配。只有第一个匹配的模式会被执行,并且它还可以提取值得组成部分赋给变量。
  最简单的形式是将一个主语值与一个或多个字面值进行比较:

def http_error(status):match status:case 400:return 'Bad Request'case 404:return 'Not found'case 418:return "I'm a teapot"case _:return "Something's wrong with the internet"

  注意最后一个代码块:“变量名”_被作为通配符并必定会匹配成功。如果没有case匹配成功,则不会执行任何分支。
  你可以用|将多个字面值组合到一个模式中:

case 401 | 403 | 404:return 'Not allowed'

  形如解包赋值的模式可被用于绑定变量:

# point是一个(x, y)元组
match point:case (0, 0):print('Origin')case (0, y):print(f"Y={y}")case (x, 0):print(f"X={x}")case (x, y):print(f"X={x}, Y={y}")case _:raise valueError('Not a point')

  第一个模式有两个字面值,可视为前述字面值模式的扩展;接下来的两个模式结合了一个字面值和一个变量,变量绑定了来自主语的一个值;第四个模式捕获了两个值,使其在概念上与解包赋值(x, y) = point类似.
  如果用类组织数据,可以用类名后借一个参数列表这种很像构造器的形式,把属性捕获到变量里:

class Point:def __init__(self, x, y):self.x = xself.y = ydef where_is(point):match point:case Point(x=0, y=0):print('Origin')case Point(x=0, y=y):print(f"Y={y}")case Point(x=x, y=0):print(f"X={x}")case Point():print('Somewhere else')case _:print('Not a point')

  一些内置类为属性提供了一个顺序,此时,可以使用位置参数。自定义类可通过在类中设置特殊属性__match_args__,为属性指定其在模式中对应的位置。若设为(“x”, “y”),则以下模式相互等价且都把属性y绑定到变量var:

Point(1, var)
Point(1, y=var)
Point(x=1, y=var)
Point(y=var, x=1)

  建议这样来阅读一个模式——通过将其视为赋值语句等号左边的一种扩展形式,来理解各个变量被设为何值。match语句只会为单一的名称(如上面的var)赋值,而不会赋值给带点号的名称(如foo.bar)、属性名(如上面的x=和y=)和类名(如上面的Point)。
  模式可以任意嵌套。举例来说,如果我们有一个由Point组成的列表,且Point添加了__match_args__时,我们可以这样来匹配它:

class Point:__match_args__ = ( 'x', 'y' )def __init__(self, x, y):self.x = xself.y = ymatch points:case []:print("No points")case [Point(0, 0)]:print("The origin")case [Point(x, y)]:print(f"Single point {x}, {y}")case [Point(0, y1), Point(0, y2)]:print(f"Two on the Y axis at {y1}, {y2}")case _:print("Something else")

  我们可以为模式添加if作为守卫子句。如果守卫子句的值为假,那么match会继续尝试匹配下一个case块。注意是先将值捕获,再对守卫子句求值:

match point:case Point(x, y) if x == y:print(f"Y=X at {x}")case Point(x, y):print('Not on the diagonal')

  该语句的一些其他关键特性:
  1. 与解包赋值类似,元组和列表模式具有完全相同的含义并且实际上都能匹配任意序列,区别是它们不能匹配迭代器或字符串。
  2. 序列模式支持扩展解包:[x, y, *rest]和(x, y, *rest)和相应的解包赋值做的事是一样的。接在*后的名称也可以为_,所以(x, y, *_)匹配含至少两项的序列,而不必绑定剩余的项。
  3. 映射模式:{“bandwidth": b, “latency”: l}从字典中捕获”bandwidth"和“latency”的值。额外的键会被忽略,这一点与序列模式不同。**rest这样的解包也支持,但是**_将会是冗余的,故不允许使用。 **rest放在字典的末尾能忽略其他键值,但是由于映射模式本身就能忽略其他键值,因此**rest是冗余的。
  4. 使用as关键字可以捕获子模式:

case (Point(x1, y1), Point(x2, y2) as p2):...

将把输入中的第二个元素捕获为p2,只要输入是包含两个点的序列。
  5. 大多数字面值是按相等性比较的,但是单例对象True、False和None是按id比较的。
  6. 模式可以使用具名常量。它们必须作为带点号的名称出现,以防止它们被解释为用于捕获的变量:

from enum import Enumclass Color(Enum):RED = 'red'GREEN = 'green'BLUE = 'blue'color = Color(input("Enter your choice of 'red', 'blue' or 'green': "))match color:case Color.RED:print("I see red!")case Color.GREEN:print("Grass is green")case Color.BLUE:print("I'm feeling the blues :(")

参考

https://docs.python.org/zh-cn/3.13/tutorial/controlflow.html

相关文章:

  • 常用的性能提升手段--提纲
  • 关于华为高斯数据库出现Invalid or unsupported by client SCRAM mechanisms定位解决的过程
  • 互斥量函数组
  • 谢飞机的Java面试之旅:从Spring Boot到Kubernetes的挑战
  • rockermq多线程消费者配置
  • 【数据可视化-38】基于Plotly得泰坦尼克号数据集的多维度可视化分析
  • 目标跟踪最新文章阅读列表
  • PlatformIO 入门学习笔记(二):开发环境介绍
  • 国标GB28181视频平台EasyGBS打造生产监控智能体系,推动企业数字化升级
  • 2025蓝桥杯省赛网络安全组wp
  • 【Nova UI】十二、打造组件库之按钮组件(上):迈向功能构建的关键一步
  • 准确--如何在自己windows电脑上安装多个nodejs版本,自由切换
  • ES练习册
  • C++ AVL树的实现
  • 《AI大模型应知应会100篇》第38篇:大模型与知识图谱结合的应用模式
  • 【创新实训项目博客】数据库搭建
  • 简单了解Java的I/O流机制与文件读写操作
  • Flink 时态维度表 Join 与缓存机制实战
  • NFC 碰一碰发视频贴牌技术,音频功能的开发实践与技术解析
  • WinForm真入门(17)——NumericUpDown控件详解
  • 中公教育薪酬透视:董监高合计涨薪122万,员工精简近三成
  • 国家发改委回应美加征关税:典型的单边主义霸凌做法
  • 梅花画与咏梅诗
  • “冲刺万亿城市”首季表现如何?温州领跑,大连GDP超徐州
  • 甘肃张掖至重庆航线开通,串起西北与西南文旅“黄金走廊”
  • 建投读书会·东西汇流|全球物品:跨文化交流视域下的明清外销瓷