数值

Python 的数值数据类型是用来存储数值的。一旦创建,数值对象的身份和类型是不可改变的。如果你改变了数值对象的值,Python 将创建一个新的数值对象。Python 支持三种不同的数值类型:

  • 整型 (int):被用来表示整数,包括正整数和负整数,不带小数点。在 Python 3 中,整数的长度是无限的,可以视为 Python 2 中的 Long 类型。此外,布尔类型(bool)实际上是整型的一种特殊形式,其中 True 和 False 分别被表示为 1 和 0。
  • 浮点型 (float):用来表示实数,由整数部分和小数部分组成。浮点型还可以使用科学计数法表示。例如,2.5e2 表示的是 2.5 乘以 10 的平方,等于 250。
  • 复数 (complex):复数由实部和虚部构成,表示形式可以是 a + bj,或者 complex(a,b)。在这里,实部 a 和虚部 b 都是浮点型。
num1 = -100      # 整数
num2 = 200.01    # 浮点数
num3 = 0xA0F     # 十六进制
num4 = 0o37      # 八进制
 
# 引入库
import math
import random
 
# 数学常量 PI 和 e
pi = math.pi
e = math.e
 
# 绝对值
abs_val = abs(num1)
 
# 向上取整
ceil_val = math.ceil(num2)
 
# 返回最大数
max_val = max(num1, num2)
 
# x**y 运算后的值
pow_val = pow(num1, num2)
 
# 随机数
random_val = random.random()
 
# x弧度的正弦值。
sin_val = math.sin(pi/2)

字符串

字符串在计算机科学和编程中非常重要。在 Python 程序中,如果我们把单个或多个字符用单引号或者双引号包围起来,我们就创建了一个字符串。

定义

# 在 Python 中,可以使用单引号(')和双引号(")来定义字符串,它们的使用方式完全相同。
s1 = 'hello, world!'
s2 = "hello, world!"
 
# 使用三个单引号(''')或者三个双引号(""")可以创建一个多行字符串。
s3 = """
hello, 
world!
"""
 
# 反斜杠(\)可以用来在字符串中插入特殊字符,这被称为转义字符。
s4 = '\n\t\141\u9a86\u660a'
 
# 在字符串前加上字符 r 可以阻止反斜杠的转义效果。
s5 = r'\n\\hello, world!\\\n' 
 
# 通过将字符串级联来创建新的字符串。
s6 = "this " "is " "string"
 
# 字符串是不可变的,这意味着你不能改变一个字符串的内容。
s6[2] = "c"    # 这将引发一个错误
 
# 字符串可以通过索引进行访问,其中 0 是第一个字符的索引,-1 是最后一个字符的索引。
s1 = 'hello, world!'
print(s1[0])  # 输出:h
print(s1[-1])  # 输出:!
 
# Python也支持字符串的切片操作,你可以使用这种方式来获取字符串的一部分。
s1 = 'hello, world!'
print(s1[0:5])  # 输出:hello
 
# ===== 字符串切片示意图 =====
| L | e | t | t | e | r | s |
|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|-7 |-6 |-5 |-4 |-3 |-2 |-1 |

转义

转义字符描述示例
\\反斜杠符号print("\\") 输出:\
\'单引号print('\'') 输出:'
\"双引号print("\"") 输出:"
\n换行print("\n") 输出一个新行
\r回车print("Hello\rWorld!") 输出:World!
\t横向制表符(Tab)print("Hello\tWorld!") 输出:Hello World!
\b退格 (Backspace)print("Hello \bWorld!") 输出:Hello World!
\f换页print("Hello \fWorld!") 输出:Hello World!
\a响铃print("\a") 执行后电脑有响声
\000print("\000") 输出:“
\v纵向制表符print("Hello \vWorld!") 输出:Hello World!
\other其他的字符以普通格式输出
\xhh二进制数,代表一个 ASCII 字符print("\x48\x65\x6c\x6c\x6f") 输出:Hello
\ooo八进制数,代表一个 ASCII 字符print("\141\142\143") 输出:abc
\uhhhh16 进制数,代表一个 Unicode 字符print("\u6211\u4eec") 输出:我们

运算

运算符描述示例
+连接字符串"Hello " + "World!" 输出:Hello World!
*重复字符串"Hello " * 3 输出:Hello Hello Hello
[]索引字符串"Hello"[1] 输出:e
[:]切片字符串"Hello"[1:4] 输出:ell
in成员运算符 - 如果字符串中包含给定的字符返回 True'H' in 'Hello' 输出:True
not in成员运算符 - 如果字符串中不包含给定的字符返回 True'H' not in 'Hello' 输出:False
%格式化字符串"Hello, %s" % 'World!' 输出:Hello, World!
f-string格式化字符串的新方式(Python 3.6+)f"Hello, {'World!'} 输出:Hello, World!

f-strings

在 Python 3.6 及以后的版本中,格式化字符串引入了更为简洁的方式,即使用 f 字符作为字符串的前缀,创建所谓的格式化字符串字面值(f-string)。通过 f-string,可以在字符串中直接插入变量值或表达式,并可以通过冒号和数字来指定输出宽度等格式化选项。

# {a:10} 表示将变量 a 插入到字符串中,并占用 10 个字符的宽度。不足 10 个字符,将使用空格进行填充。
 
a, b = 5, 10
print(f'{a:10} * {b:10} = {a * b}')

PEP 701 的更新

在 Python 3.11 版本中,f-strings 还存在一些限制,导致在某些情况下使用起来不够灵活。PEP 701 对 f-strings 进行了一些更新,解除了一些限制,使得 f-strings 可以更灵活地使用,包括以下方面的更新:

在 Python 3.12 版本中,对 f-strings 进行了更新,解除了之前的一些限制,使得 f-strings 更加灵活和强大。更新主要包括以下方面:

引号重用

在 Python 3.11 中,f-string 的表达式组件使用与包含 f-string 相同的引号会导致 SyntaxError。而在 Python 3.12 中,可以重用引号,不再限制引号的使用。

songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism']
result1 = f"This is the playlist: {', '.join(songs)}"
print(result1)
# 输出:'This is the playlist: Take me back to Eden, Alkaline, Ascensionism'
多行表达式和注释

在 Python 3.11 中,f-string 的表达式必须在一行内定义,即使外部表达式可以跨多行,这会使得代码可读性变差。而在 Python 3.12 中,可以定义跨多行的表达式,并且可以包含注释,提高了代码的可读性。

result2 = f"This is the playlist: {', '.join([
    'Take me back to Eden',  # My, my, those eyes like fire
    'Alkaline',              # Not acid nor alkaline
    'Ascensionism'           # Take to the broken skies at last
])}"
print(result2)
# 输出:'This is the playlist: Take me back to Eden, Alkaline, Ascensionism'
反斜杠和 Unicode 字符

在 Python 3.11 中,f-string 的表达式不能包含任何反斜杠字符,也不能包含 Unicode 转义序列。而在 Python 3.12 中,可以包含反斜杠和 Unicode 字符,使得表达式更加灵活。

songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism']
 
result3 = f"This is the playlist: {'\n'.join(songs)}"
print(result3)
# 输出:
# This is the playlist: Take me back to Eden
# Alkaline
# Ascensionism
 
result4 = f"This is the playlist: {'\N{BLACK HEART SUIT}'.join(songs)}"
print(result4)
# 输出:'This is the playlist: Take me back to Eden♥Alkaline♥Ascensionism'

以上代码展示了 Python 3.12 中 f-strings 的更新。可以看到,我们可以在 f-string 中使用引号重用,多行表达式和注释,以及包含反斜杠和 Unicode 字符的表达式,这些更新使得 f-strings 更加灵活和强大,更方便地进行字符串格式化。同时,通过使用 PEG 解析器实现的更新,使得错误消息更加准确,有助于代码调试。

常用方法

函数描述示例
len(str)返回字符串长度len('hello, world!') 输出结果:13
str.capitalize()返回首字母大写的字符串'hello, world!'.capitalize() 输出结果:Hello, world!
str.title()返回每个单词首字母大写的字符串'hello, world!'.title() 输出结果:Hello, World!
str.upper()返回字符串变大写后的拷贝'hello, world!'.upper() 输出结果:HELLO, WORLD!
str.find(sub)查找子串在字符串中的起始位置,未找到返回 -1'hello, world!'.find('or') 输出结果:8
str.startswith(prefix)检查字符串是否以指定的前缀开头'hello, world!'.startswith('He') 输出结果:False
str.endswith(suffix)检查字符串是否以指定的后缀结尾'hello, world!'.endswith('!') 输出结果:True
str.center(width, fillchar)将字符串以指定宽度居中并在两侧填充指定字符'hello'.center(10, '*') 输出结果:hello
str.rjust(width, fillchar)将字符串以指定宽度靠右并在左侧填充指定字符'hello'.rjust(10, '*') 输出结果:*****hello
str.isdigit()检查字符串是否由数字构成'abc123456'.isdigit() 输出结果:False
str.isalpha()检查字符串是否由字母构成'abc123456'.isalpha() 输出结果:False
str.isalnum()检查字符串是否由字母和数字构成'abc123456'.isalnum() 输出结果:True
str.strip()返回修剪左右两侧空格之后的字符串' jackfrued@126.com '.strip() 输出结果:‘jackfrued@126.com

列表

列表(list)是一种结构化的、非标量类型,它是值的有序序列,每个值都可以通过索引进行标识,定义列表可以将列表的元素放在 [] 中,多个元素用 , 进行分隔,可以使用 for 循环对列表元素进行遍历,也可以使用 [][:] 运算符取出列表中的一个或多个元素。

定义

# 列表定义
list1 = [ 'abcd', 786, 2.23, 'runoob', 70.2 ]
tinylist = [123, 'runoob']
 
# 输出完整列表
print(list1)  # 输出结果:['abcd', 786, 2.23, 'runoob', 70.2]
 
# 输出列表第一个元素
print(list1[0])  # 输出结果:'abcd'
 
# 从第二个开始输出到第三个元素
print(list1[1:3])  # 输出结果:[786, 2.23]
 
# 输出从第三个元素开始的所有元素
print(list1[2:])  # 输出结果:[2.23, 'runoob', 70.2]
 
# 输出两次列表
print(tinylist * 2)  # 输出结果:[123, 'runoob', 123, 'runoob']
 
# 连接列表
print(list1 + tinylist)  # 输出结果:['abcd', 786, 2.23, 'runoob', 70.2, 123, 'runoob']
 
# 通过循环用下标遍历列表元素
for index in range(len(list1)):
    print(list1[index])
 
# 通过for 循环遍历列表元素
for elem in list1:
    print(elem)
 
# 通过 enumerate 函数处理列表之后再遍历可以同时获得元素索引和值
for index, elem in enumerate(list1):
    print(index, elem)

运算

# 创建列表
list1 = [1, 2, 3]
list2 = [4, 5, 6]
 
# 连接列表,返回一个新的列表
list3 = list1 + list2
print(list3)  # 输出:[1, 2, 3, 4, 5, 6]
 
# 复制列表,返回一个新的列表
list4 = list1 * 3
print(list4)  # 输出:[1, 2, 3, 1, 2, 3, 1, 2, 3]
 
# 计算元素个数
length = len(list1)
print(length)  # 输出:3
 
# 判断元素是否在列表中
result = 4 in list1
print(result)  # 输出:False
 
result = 2 in list1
print(result)  # 输出:True
 
# 访问元素,可以使用索引,索引从0开始
elem = list1[0]
print(elem)  # 输出:1
 
# 切片操作
list5 = list1[1:3]
print(list5)  # 输出:[2, 3]
 
# 切片时可以指定步长
list6 = list1[0:3:2]
print(list6)  # 输出:[1, 3]
 
# 切片时可以省略开始或结束索引
list7 = list1[:2]
list8 = list1[1:]
print(list7)  # 输出:[1, 2]
print(list8)  # 输出:[2, 3]
 
# 反向切片
list9 = list1[::-1]
print(list9)  # 输出:[3, 2, 1]
 
# 修改元素值
list1[0] = 100
print(list1)  # 输出:[100, 2, 3]
 
# 列表末尾添加元素
list1.append(4)
print(list1)  # 输出:[100, 2, 3, 4]
 
# 列表末尾删除元素
list1.pop()
print(list1)  # 输出:[100, 2, 3]
 
# 指定位置插入元素
list1.insert(1, 200)
print(list1)  # 输出:[100, 200, 2, 3]
 
# 删除指定位置的元素
del list1[2]
print(list1)  # 输出:[100, 200, 3]
 
# 清空列表
list1.clear()
print(list1)  # 输出:[]

常用方法

函数描述
len(list)返回列表元素的个数。
list.append(x)在列表末尾添加元素 x
list.insert(i, x)在指定位置 i 前插入元素 x
list.extend(iterable)将可迭代对象中的元素逐个添加到列表。
list.remove(x)删除列表中第一个值为 x 的元素。
list.pop([i])移除并返回列表中指定位置 i 处的元素。如果未指定索引,默认删除并返回最后一个元素。
list.clear()清空列表中的所有元素。
list.index(x[, start[, end]])返回列表中第一个值为 x 的元素的索引。如果未找到该元素,会引发 ValueError 异常。
list.count(x)返回元素 x 在列表中出现的次数。
list.sort(key=None, reverse=False)对列表进行排序,如果指定参数 key 则按照 key 进行排序,如果指定参数 reverse 则为降序。
list.reverse()将列表中的元素倒序排列。
list.copy()返回列表的浅拷贝,即创建一个新列表并复制原列表中的元素。

元组

Python 中的元组是一种容器数据类型,使用小括号 () 定义,类似于列表,但元组的元素不能修改,是不可变的。元组用于存储多个数据,可以包含不同类型的元素。与列表不同,元组在定义时可以省略括号,但在实际使用中建议加上括号,以增强代码的可读性。

img

定义

# 定义元组
t = ('骆昊', 38, True, '四川成都')
 
# 定义空元组
t1 = ()
 
# 元组中只包含一个元素时,需要在元素后面添加逗号 `,`,否则括号会被当作运算符使用。
tup1 = (50)          # 不加逗号,类型为整型
tup1 = (50,)         # 加上逗号,类型为元组
 
# 遍历元组中的值
for member in t:
    print(member)
 
# 重新给元组赋值
# t[0] = '王大锤'  # TypeError,元组不可修改
# 变量t重新引用了新的元组,原来的元组将被垃圾回收
t = ('王大锤', 20, True, '云南昆明')
 
# 将元组转换成列表
person = list(t)
 
# 将列表转换成元组
fruits_list = ['apple', 'banana', 'orange']
fruits_tuple = tuple(fruits_list)
 
# 创建一个新的元组
tup1 = (12, 34.56)
tup2 = ('abc', 'xyz')
tup3 = tup1 + tup2
 
# 删除元组
tup = ('Google', 'Runoob', 1997, 2000)
del tup

运算

# 创建元组
tup1 = (1, 2, 3)
tup2 = (4, 5, 6)
 
# 连接元组,返回一个新的元组
tup3 = tup1 + tup2
print(tup3)  # 输出:(1, 2, 3, 4, 5, 6)
 
# 复制元组,返回一个新的元组
tup4 = tup1 * 3
print(tup4)  # 输出:(1, 2, 3, 1, 2, 3, 1, 2, 3)
 
# 计算元素个数
length = len(tup1)
print(length)  # 输出:3
 
# 判断元素是否在元组中
result = 4 in tup1
print(result)  # 输出:False
 
result = 2 in tup1
print(result)  # 输出:True
 
# 访问元素,可以使用索引,索引从0开始
elem = tup1[0]
print(elem)  # 输出:1
 
# 切片操作
tup5 = tup1[1:3]
print(tup5)  # 输出:(2, 3)
 
# 切片时可以指定步长
tup6 = tup1[0:3:2]
print(tup6)  # 输出:(1, 3)
 
# 切片时可以省略开始或结束索引
tup7 = tup1[:2]
tup8 = tup1[1:]
print(tup7)  # 输出:(1, 2)
print(tup8)  # 输出:(2, 3)
 
# 反向切片
tup9 = tup1[::-1]
print(tup9)  # 输出:(3, 2, 1)

常用方法

函数描述
len(tuple)返回元组中元素的个数。
tuple.count(x)返回元组中元素 x 出现的次数。
tuple.index(x[, start[, end]])返回元组中第一个值为 x 的元素的索引。如果未找到该元素,会引发 ValueError 异常。
tuple + tuple将两个元组连接成一个新的元组。
tuple * n将元组重复 n 次。
x in tuple判断元素 x 是否在元组中,如果在返回 True,否则返回 False
x not in tuple判断元素 x 是否不在元组中,如果不在返回 True,否则返回 False

集合

集合(set)是由不重复元素组成的无序容器。基本用法包括成员检测、消除重复元素。集合对象支持合集、交集、差集、对称差分等数学运算。

定义

集合可以通过花括号 {}set() 函数创建。注意,创建空集合只能用 set(),不能用 {},因为 {} 创建的是空字典。

# 创建集合
set1 = {1, 2, 3, 4, 5}
set2 = {3, 4, 5, 6, 7}
set3 = {5, 6, 7, 8, 9}
 
# 判断元素是否在集合内
3 in set1       # True
10 in set1      # False
 
# 添加元素
set1.add(6)     # {1, 2, 3, 4, 5, 6}
set1.add(7)     # {1, 2, 3, 4, 5, 6, 7}
set1.add(3)     # {1, 2, 3, 4, 5, 6, 7},重复的元素不会被添加
 
# 删除元素
set1.remove(4)  # {1, 2, 3, 5, 6, 7}
set1.discard(6) # {1, 2, 3, 5, 7}
set1.discard(8) # {1, 2, 3, 5, 7},如果元素不存在,discard 方法不会引发异常
 
# 元素个数
len(set1)       # 5
 
# 清空集合
set1.clear()    # set()

运算

set1 = {1, 2, 3, 4, 5}
set2 = {3, 4, 5, 6, 7}
set3 = {5, 6, 7, 8, 9}
 
# 交集
set1 & set2         # {3, 4, 5}
 
# 并集
set1 | set2         # {1, 2, 3, 4, 5, 6, 7}
 
# 差集
set1 - set2         # {1, 2}
 
# 对称差运算(在 set1 或 set2 中,但不会同时出现在二者中)
set1 ^ set2         # {1, 2, 6, 7}
 
# 判断子集和超集
set2 <= set1        # False,set2 是 set1 的子集吗?
set3 <= set1        # False,set3 是 set1 的子集吗?
set1 >= set2        # False,set1 是 set2 的超集吗?
set1 >= set3        # False,set1 是 set3 的超集吗?

常用方法

函数描述
set.add(x)将元素 x 添加到集合中
set.remove(x)删除集合中的元素 x,如果 x 不在集合中会引发 KeyError
set.discard(x)删除集合中的元素 x,如果 x 不在集合中不会引发异常
set.pop()随机删除集合中的一个元素,并返回删除的元素
set.clear()清空集合中的所有元素
len(set)返回集合中元素的个数
x in set判断元素 x 是否在集合中,如果在返回 True,否则返回 False
set1.isdisjoint(set2)判断两个集合是否没有共同的元素,如果没有返回 True,否则返回 False
set1.issubset(set2)判断集合 set1 是否是集合 set2 的子集,如果是返回 True,否则返回 False
set1.issuperset(set2)判断集合 set1 是否是集合 set2 的超集,如果是返回 True,否则返回 False
set1.union(set2)返回集合 set1 和 set2 的并集
set1.intersection(set2)返回集合 set1 和 set2 的交集
set1.difference(set2)返回集合 set1 和 set2 的差集,即在 set1 中但不在 set2 中的元素
set1.symmetric_difference(set2)返回集合 set1 和 set2 的对称差集,即在 set1 或 set2 中,但不会同时出现在二者中的元素
set1.update(set2)将集合 set2 中的元素添加到 set1 中
set1.intersection_update(set2)将集合 set1 中不在 set2 中的元素删除
set1.difference_update(set2)将集合 set1 和 set2 的差集中的元素从 set1 中删除
set1.symmetric_difference_update(set2)将集合 set1 和 set2 的对称差集中的元素添加到 set1 中
set.copy()返回集合的浅拷贝
set.pop()随机删除并返回集合中的一个元素

字典

img

字典是另一种可变容器模型,且可存储任意类型对象。字典与列表、集合不同的是,它是一种键 - 值(key-value)对应的数据结构。每个元素都是由一个键和一个值组成的键值对,键和值通过冒号分开。键必须是唯一的,但值则不必。

img

定义

# 使用大括号创建字典
person = {'name': 'John', 'age': 30, 'city': 'New York'}
 
# 使用 dict() 创建字典
empty_dict = dict()
 
# 访问字典中的元素
print(person['name'])  # 输出:John
print(person['age'])   # 输出:30
print(person['city'])  # 输出:New York

运算

# 修改字典中的元素
person['age'] = 31
print(person)  # 输出:{'name': 'John', 'age': 31, 'city': 'New York'}
 
# 添加新的键值对
person['job'] = 'Engineer'
print(person)  # 输出:{'name': 'John', 'age': 31, 'city': 'New York', 'job': 'Engineer'}
 
# 删除字典中的元素
del person['city']
print(person)  # 输出:{'name': 'John', 'age': 31, 'job': 'Engineer'}
 
# 清空字典
person.clear()
print(person)  # 输出:{}
 
# 遍历字典的键
for key in person:
    print(key)
 
# 遍历字典的值
for value in person.values():
    print(value)
 
# 遍历字典的键值对
for key, value in person.items():
    print(key, value)
 
# 判断键是否存在
if 'name' in person:
    print("Name exists.")
 

常用方法

方法描述
keys()返回字典所有键的列表
values()返回字典所有值的列表
items()返回字典所有键值对的元组列表
get(key, default=None)返回指定键的值,如果键不存在,返回默认值
pop(key)删除指定键的值,并返回该键对应的值
popitem()随机删除一个键值对,并返回该键值对
clear()删除字典中的所有键值对
update(other_dict)将其他字典的键值对更新到当前字典
copy()返回字典的浅拷贝(复制字典中的键值对)

推导式

推导式是一种强大的 Python 特性,可以快速、简洁地创建新的数据序列。它可以从一个数据序列构建另一个新的数据序列的结构体。

列表

列表推导式是最常用的推导式,它通过在一个可迭代对象上应用表达式来创建一个新的列表。

# 语法
new_list = [out_exp_res for out_exp in input_list]
new_list = [out_exp_res for out_exp in input_list if condition]
 
# 示例
multiples = [i for i in range(30) if i % 3 == 0]
print(multiples)  # 输出:[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

字典

# 语法
new_dict = {key_expr: value_expr for value in collection}
new_dict = {key_expr: value_expr for value in collection if condition}
 
# 示例
dic = {x: x**2 for x in (2, 4, 6)}
print(dic)  # 输出:{2: 4, 4: 16, 6: 36}

集合

# 语法
new_set = {expression for item in sequence}
new_set = {expression for item in sequence if conditional}
 
# 示例
a = {x for x in 'abracadabra' if x not in 'abc'}
print(a)  # 输出:{'d', 'r'}

元组

# 语法
new_tuple = (expression for item in sequence)
new_tuple = (expression for item in sequence if conditional)
 
# 示例
a = (x for x in range(1, 10))
print(a)          # 输出:<generator object <genexpr> at 0x7f900dfdd200>
print(tuple(a))   # 输出:(1, 2, 3, 4, 5, 6, 7, 8, 9)

其他

f = [x for x in range(1, 10)]
print(f)
 
f = [x + y for x in 'ABCDE' for y in '1234567']
print(f)
 
f = [x ** 2 for x in range(1, 1000)]
print(sys.getsizeof(f))  # 查看对象占用内存的字节数
print(f)
 
# 生成器表达式,不占用额外内存
f = (x ** 2 for x in range(1, 1000))
print(sys.getsizeof(f))  # 相比列表生成式,生成器不占用存储数据的空间
print(f)
for val in f:
    print(val)
 

迭代器

可迭代对象是 Python 中的一种数据结构,例如列表、元组、字典、字符串等都是可迭代对象。迭代器是一种特殊的可迭代对象,它可以通过调用 iter() 函数获取,然后使用 next() 函数逐个访问元素。迭代器在其生命周期中,会有四个状态:GEN_CREATEDGEN_RUNNINGGEN_SUSPENDEDGEN_CLOSED

graph LR
    A[生成器已创建] --> B[解释器执行中]
    B --> C[在 yield 表达式处暂停]
    C --> D[解释器执行中]
    D --> C
    D --> E[生成器执行结束]
  • iter():创建迭代器。
  • next():输出迭代器的下一个元素。
s = 'abc'
it = iter(s)
 
print(it)         # 输出:<str_iterator object at 0x10c90e650>
print(next(it))   # 输出:'a'
print(next(it))   # 输出:'b'
print(next(it))   # 输出:'c'
 
# 抛出异常
# 迭代器用尽后会引发 StopIteration 异常
try:
    print(next(it))
except StopIteration:
    print("迭代器用尽了。")
 

生成器

生成器是一种特殊的迭代器,它是一个可以像迭代器一样使用 for 循环来获取元素的函数。生成器函数使用 yield 关键字将一个普通函数改造成生成器函数,yield 相当于 return 但有所不同,yield 虽然返回了值但函数并没有结束,而是暂停在 yield 处,下次调用 next() 或循环迭代时会从 yield 处继续执行。生成器在其生命周期中会有四个状态:GEN_CREATEDGEN_RUNNINGGEN_SUSPENDEDGEN_CLOSED

graph LR
    A[生成器函数被调用] --> B[生成器已创建]
    B --> C[解释器执行中]
    C --> D[在 yield 表达式处暂停]
    D --> C
    C --> E[生成器执行结束]

    F[生成器已创建] --> G[GEN_CREATED]
    G --> H[生成器正在执行]
    H --> I[GEN_RUNNING]
    I --> J[在 yield 表达式处暂停]
    J --> H
    I --> K[生成器执行结束]
    K --> L[GEN_CLOSED]

生成器在其生命周期中,会有如下四个状态:

  • GEN_CREATED:生成器已创建,还未被激活。
  • GEN_RUNNING:解释器正在执行(只有在多线程应用中才能看到这个状态)。
  • GEN_SUSPENDED:在 yield 表达式处暂停。
  • GEN_CLOSED:生成器执行结束。
def fibonacci(n):
    a, b, counter = 0, 1, 0
    while True:
        if counter > n:
            return
        yield a
        a, b = b, a + b
        counter += 1
 
for i in fibonacci(10):
    print(i, end=" ")  # 输出:0 1 1 2 3 5 8 13 21 34 55