一、概念进阶
容器(container):指的是那些用于存储和组织其他对象的数据结构。在python中常见的数据容器有列表、元组、集合、字典等。
迭代(iterate):是一种重复获取数据集中元素的过程,一次只获取一个元素,直到遍历完所有元素。每一次获取或处理得到的结果会作为下一次迭代的初始值(这一次结果依赖上一次数据)。
1. 容器(container)
在 Python 中,选择数据容器的性能取决于具体使用场景。以下是几种常见的数据容器性能对比,可以看出dict和set在
大型的数据集上有着明显的性能优势。
-
list
: 适用于需要快速随机访问和追加的场景,但在中间插入或删除元素时性能较差。 -
tuple
: 类似于列表,但不可变,适用于需要固定数据集合且速度较快的场景。 -
set
: 对于需要高效查找、添加和删除操作的场景,性能最优,因为其底层实现基于哈希表。 -
dict
: 对于需要根据键进行高效查找、插入和删除的场景,性能最优,同样基于哈希表。
2. 迭代器(iterator)
在Python中,迭代器是一个对象,允许一次访问一个元素,而不需要存储整个序列。迭代器实现了两个核心方法:
1. __iter__()
,它返回迭代器对象自身。
2. __next__()
,它返回序列的下一个元素。
当序列的元素全部被访问过之后,__next__()
方法会抛出 StopIteration
异常,标志着迭代结束。同一迭代器只能被迭代一次(避免无限次迭代出现死循环)。
迭代协议:任何类只要实现了__iter__
和__next__
方法,就满足了迭代器协议。
1.1 如何得到迭代器
python中有一些内置的函数会返回迭代器,这里列举了部分。
# 1. iter()函数
list_1 = [1, 2, 3, 4, 5]
iterator = iter(list_1)
print(next(iterator))
# 2. range()函数
for i in range(5):
print(i)
# 3. enumerate()函数
letter = ['A', 'B', 'C']
for index, fruit in enumerate(letter):
print(f"Index: {index}, Fruit: {letter}")
# 4. reversed()函数
list_1 = [1, 2, 3, 4, 5]
for item in reversed(list_1): # 反向迭代
print(item)
# 5. zip()函数
list_1 = [1, 2, 3]
list_2 = [4, 5, 6]
for item in zip(list_1, list_2):
print(item)
# 6. map()函数
numbers = [1, 2, 3, 4]
squared = map(lambda x: x ** 2, numbers)
print(list(squared)) # 输出 [1, 4, 9, 16]
1.2 迭代器的好处
懒加载:迭代器按需生成数据,而不是一次性加载所有数据到内存中。这在处理大量数据时特别有用,可以显著降低内存使用。比如,在处理大文件或流数据时,迭代器可以逐步读取数据,避免了内存溢出的风险。
节省资源:通过逐步生成数据,迭代器可以在处理大规模数据时节省计算资源。
1.3 与可迭代对象的区别
可迭代对象(iterable)是一个实现了 __iter__()
方法或 __getitem__()
方法的对象。可以使用for循环等遍历。列表、元组、字典、集合、字符串等都是可迭代对象。(不能调用next()
方法)
3. 生成器
生成器:特殊的迭代器。与迭代器的区别在于:迭代器是访问容器的一种方式(容器已经出现),生成器则是从已有元素拓印出一份副本,只为此次迭代使用。
3.1 生成器函数
生成器函数是一个特殊类型的函数,用于生成迭代器。生成器函数使用 yield
语句来返回值,而不是 return
。每次调用 yield
时,函数会暂停执行,并将当前的值返回。下一次调用生成器时,函数从上次暂停的地方继续执行。生成器函数可以处理大量数据时特别有用,因为它们不会一次性加载所有数据,而是按需生成数据。
return
用于从函数中返回一个值,并终止函数的执行。当return
语句被执行时,函数会立即结束,控制权会返回到函数调用处。
yield
用于生成一个生成器(generator),它允许函数在每次调用时返回一个值,但保留函数的执行状态。每次迭代生成器时,函数会从上次yield
停止的地方继续执行,直到下一个yield。
def yield_test():
print('这一行被执行')
list_A = [1, 2, 3, 4, 5]
for i in list_A:
yield i
print('finish')
yield 7
print('finish,too')
if __name__ == '__main__':
run_test = yield_test()
print(next(run_test)) # 打印这一行被执行, 1
print(next(run_test)) # 2
print(next(run_test)) # 3
print(next(run_test)) # 4
print(next(run_test)) # 5
print(next(run_test)) # 打印finish, 7
print(next(run_test)) # 打印finish,too 并抛出异常
3.2 生成器表达式与列表表达式
生成器表达式用于生成一个生成器对象,该对象是一个迭代器,按需生成数据。其语法形式类似于列表表达式,但使用圆括号( )
。
列表表达式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的列表,使用圆括号[ ]。
# 列表表达式
[expression for item in iterable if condition]
# 生成器表达式
(expression for item in iterable if condition)
# 使用条件的列表表达式
squares_list = [x ** 2 for x in range(1, 6) if x ** 2 > 10]
print("列表表达式生成的列表(条件:平方数 > 10):", squares_list)
# 使用条件的生成器表达式
squares_gen = (x ** 2 for x in range(1, 6) if x ** 2 > 10)
print("生成器表达式生成的生成器对象(条件:平方数 > 10):", squares_gen)
# 逐个访问生成器的值
for square in squares_gen:
print(square)
二、代码技巧
1. range函数
1.range(stop)
: 从 0 开始,到 stop
结束,但不包括 stop
。
for i in range(5): # [0, 1, 2, 3, 4]
print(i)
2.range(start, stop)
: 从 start
开始,到 stop
结束,但不包括 stop
。
for i in range(5): # [0, 1, 2, 3, 4]
print(i)
3.range(start, stop, step)
: 从 start
开始,到 stop
结束,但不包括 stop
,每次增加 step
。
for i in range(0, 10, 2): # [0, 2, 4, 6, 8]
print(i)
2. zip函数
zip
返回一个迭代器,其中每个元素都是一个元组,包含了来自所有输入可迭代对象的对应位置上的元素。
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
zipped = zip(list1, list2)
print(list(zipped)) # 输出: [(1, 'a'), (2, 'b'), (3, 'c')]
当输入的可迭代对象长度不相等时,zip
会以最短的可迭代对象为准,截断多余的部分。
list1 = [1, 2, 3]
list2 = ['a', 'b']
zipped = zip(list1, list2)
print(list(zipped)) # 输出: [(1, 'a'), (2, 'b')]
*zipped
是解包操作,将 zipped
元素(元组)解开成多个参数,传递给 zip
函数。zip
函数重新打包这些元素,将它们转置。
python
list1 = [1, 2, 3]
list2 = ['a', 'b']
zipped = zip(list1, list2)
print(list(zipped)) # 输出: [(1, 'a'), (2, 'b')]
3. 快速合并两个字典
dictionary_one = {"a": 1, "b": 2}
dictionary_two = {"c": 3, "d": 4}
merged = {**dictionary_one, **dictionary_two}
print(merged)
# {'a': 1, 'b': 2, 'c': 3, 'd': 4}
4. enumerate()函数
enumerate()
函数用于将一个可迭代对象(如列表、元组等)转化为一个迭代器,该迭代器生成包含索引和元素的元组。
# enumerate(iterable, start=0) start为起始索引
fruits = ['apple', 'banana', 'mango']
for index, fruit in enumerate(fruits):
print(index, fruit)
# 0 apple
# 1 banana
# 2 mango
5. python路径表示
python中的转义字符为 \
,所以在Windows环境下,一些路径不经过处理无法正确表达,有以下解决方法。
1. 在原始字符串之前添加 r(raw string)
,不对其中的反斜杠转义处理。
path = r"C:\Users\Username\Documents\file.txt"
2. 使用双反斜杠。
path = "C:\\Users\\Username\\Documents\\file.txt"
3. python中允许使用 /
作为路径分隔符,且该路径在MacOS和Linux也能正确解析。
path = "C:/Users/Username/Documents/file.txt"
4. 使用 os.path.join()
或 pathlib.Path
:这两种方法提供了跨平台的路径处理方式。os.path.join()
根据操作系统自动选择适当的路径分隔符,而 pathlib.Path
提供了更加OOP的路径操作接口。
# os.path.join()
import os
folder = 'documents'
filename = 'example.txt'
full_path = os.path.join(folder, filename)
# pathlib.Path
from pathlib import Path
path = Path("C:/Users/Username/Documents/file.txt")
6. lambda表达式
lambda
表达式是 Python 中用于创建匿名函数的简便工具。基本语法是 lambda 参数: 表达式
,其中表达式的计算结果就是函数的返回值。
add = lambda x, y: x + y
print(add(3, 5)) # 输出 8
7. map()函数
map()
用于将指定函数应用于可迭代对象(如列表)中的每个元素。返回一个迭代器,包含应用函数后的结果。
list1 = [1, 2, 3]
list2 = [4, 5, 6]
sum_list = list(map(lambda x, y: x + y, list1, list2))
print(sum_list) # 输出: [5, 7, 9]