- 列表推导式对可读性的影响
# 基于字符串构建一个Unicode码点列表
symbols = '$%^&*'
codes = []
for symbol in symbols:
codes.append(ord(symbol))
codes [36, 37, 94, 38, 42]
# 使用列表推导式基于一个字符串构建一个Unicode码点列表
symbols = '$%^&*'
codes = [ord(symbol) for symbol in symbols]
codes[36, 37, 94, 38, 42]
上述示例中,列表推导式更容易理解,如果超过两行,最好把语句拆开,或者使用传统的for循环重写。
- 列表推导式与map和filter比较
# 使用列表推导式和map/filter组合构建同一个列表
symbols = '$%^&*'
beyond_ascii = [ord(s) for s in symbols if ord(s) > 36]
beyond_ascii[37, 94, 38, 42]
beyond_ascii = list(filter(lambda c: c > 36, map(ord, symbols)))
beyond_ascii[37, 94, 38, 42]
- 笛卡尔积
# 使用列表推导式计算笛卡尔积
colors = ['black', 'white']
sizes = ['S', 'M', 'L']
tshirts = [(color, size) for color in colors for size in sizes]
tshirts[('black', 'S'),
('black', 'M'),
('black', 'L'),
('white', 'S'),
('white', 'M'),
('white', 'L')]
for color in colors:
for size in sizes:
print((color, size))('black', 'S')
('black', 'M')
('black', 'L')
('white', 'S')
('white', 'M')
('white', 'L')
tshirts = [(color, size) for size in sizes
for color in colors]
tshirts[('black', 'S'),
('white', 'S'),
('black', 'M'),
('white', 'M'),
('black', 'L'),
('white', 'L')]
- 生成器表达式
# 使用生成器表达式构建一个元组和数组
symbols = '$%^&*'
tuple(ord(symbol) for symbol in symbols)(36, 37, 94, 38, 42)
import array
array.array('I', (ord(symbol) for symbol in symbols))array('I', [36, 37, 94, 38, 42])
# 使用生成器表达式计算笛卡尔积
colors = ['black', 'white']
sizes = ['S', 'M', 'L']
for tshirt in (f'{c} {s}' for c in colors for s in sizes):
print(tshirt)black S
black M
black L
white S
white M
white L
上述示例不会构建6种T恤衫组合的列表。
- 把元组当作记录使用
lax_coordinates = (33.9425, -118.408056)
city, year, pop, chg, area = ('Tokyo', 2003, 32_450, 0.66, 8014)
traveler_ids = [('USA', '31195855'), ('BRA', 'CE243567'), ('ESP', 'XDA205856')]
for passport in sorted(traveler_ids):
print('%s/%s' % passport)BRA/CE243567
ESP/XDA205856
USA/31195855
for country, _ in traveler_ids:
print(country)USA
BRA
ESP
- 并行赋值
lax_coordinates = (33.9425, -118.408056)
latitude, longitude = lax_coordinates
latitude, longitude(33.9425, -118.408056)
- 使用*获取余下的项
并行赋值时,*前缀只能应用到一个变量上,可以是任何位置上的变量。
a, b, *rest = range(5)
a, b, rest(0, 1, [2, 3, 4])
a, *body, c, d = range(5)
a, body, c, d(0, [1, 2], 3, 4)
- 嵌套拆包
metro_areas = [
('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833))
]
print(f'{"":15} | {"latitude":>9} | {"longitude":>9}')
for name, _, _, (lat, lon) in metro_areas:
if lon <= 0:
print(f'{name:15} | {lat:9.4f} | {lon:9.4f}') | latitude | longitude
Mexico City | 19.4333 | -99.1333
New York-Newark | 40.8086 | -74.0204
Sao Paulo | -23.5478 | -46.6358
metro_areas = [
('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833))
]
print(f'{"":15} | {"latitude":>9} | {"longitude":>9}')
for record in metro_areas:
match record:
case [name, _, _, (lat, lon)] if lon <= 0:
print(f'{name:15} | {lat:9.4f} | {lon:9.4f}') | latitude | longitude
Mexico City | 19.4333 | -99.1333
New York-Newark | 40.8086 | -74.0204
Sao Paulo | -23.5478 | -46.6358
匹配序列模式的条件:
- 匹配对象是序列。
- 匹配对象和模式的项数相等。
- 对应的项相互匹配,包括嵌套的项。
# 从纯文本形式的发票中提取商品信息
invoice = """
0.....6.................................40........52...55........
1909 Pimoroni PiBrella $17.50 3 $52.50
1489 6mm Tactile Switch x20 $4.95 2 $9.90
1510 Panavise Jr. - PV-201 $28.00 1 $28.00
1601 PiTFT Mini Kit 320x240 $34.95 1 $34.95
"""
SKU = slice(0, 6)
DESCRIPTION = slice(6, 40)
UNIT_PRICE = slice(40, 52)
QUANTITY = slice(52, 55)
ITEM_TOTAL = slice(55, None)
line_items = invoice.split('\n')[2:]
for item in line_items:
print(item[UNIT_PRICE], item[DESCRIPTION]) $17.50 Pimoroni PiBrella
$4.95 6mm Tactile Switch x20
$28.00 Panavise Jr. - PV-201
$34.95 PiTFT Mini Kit 320x240
如果一个列表只包含数值,使用array.array会更高效。
from array import array
from random import random# 创建一个双精度浮点数数组
floats = array('d', (random() for i in range(10**7)))
floats[-1]0.4197427599509004
# 把数组存入一个二进制文件中
fp = open('./data/floats.bin', 'wb')
floats.tofile(fp)
fp.close()# 从二进制文件中读取1000万个数
floats2 = array('d')
fp = open('./data/floats.bin', 'rb')
floats2.fromfile(fp, 10**7)
fp.close()floats2[-1]0.4197427599509004
floats2 == floatsTrue
内置的menoryview类是一种共享内存的序列类型,可在不复制字节的情况下处理数组的切片。
- 分别以1x6、2x3和3x2矩阵的视图处理6字节内存
from array import array
octets = array('B', range(6))m1 = memoryview(octets)
m1.tolist()[0, 1, 2, 3, 4, 5]
# 构建2x3的矩阵
m2 = m1.cast('B', [2,3])
m2.tolist()[[0, 1, 2], [3, 4, 5]]
# 构建3x2的矩阵
m3 = m1.cast('B', [3, 2])
m3.tolist()[[0, 1], [2, 3], [4, 5]]
# octets、m1、m2、m3之间的内存是共享的
m2[1,1] = 22
m3[1,1] = 33
octetsarray('B', [0, 1, 2, 33, 22, 5])
- 修改一个16位整数数组中某一项的字节,改变该项的值
numbers = array('h', [-2, -1, 0, 1, 2])
memv = memoryview(numbers)
len(memv)5
memv[0]-2
memv_oct = memv.cast('B')
memv_oct.tolist()[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
memv_oct[5] = 4
numbersarray('h', [-2, -1, 1024, 1, 2])
- deque类实现一种线程安全的双端队列,旨在快速在两端插入和删除项。
- queue提供几个同步(即线程安全)队列类,在队列填满后,阻塞插入新项,等待其他线程从队列中取出一项。
- multiprocessiong单独实现了无界SimpleQueue和有界的Queue。
- asyncio提供了Queue、LifoQueue、PriorityQueue和JoinableQueue,为管理异步编程任务而做了修改。
# 处理一个deque对象
from collections import deque
dq = deque(range(10), maxlen=10)
dqdeque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
# 轮转。当n>0时,从右端取几项放到左端,当n<0时,从左端取几项放到右端。
dq.rotate(3)
print(dq)
dq.rotate(-4)
print(dq)deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
# 在已满的队列中的一端追加,另一端要丢弃
dq.appendleft(-1)
dqdeque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
dq.extend([11, 22, 33])
dqdeque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
dq.extendleft([10, 20, 30, 40])
dqdeque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)
-
元组的本质:ABC语言的compound类型是Python元组的前身。该类型还支持并行复制,也可用作字典的组合键。但是不是序列,不可迭代,不饿能通过索引获取字段,不能使用切片。
-
扁平序列与容器序列:
- 扁平序列:是不可嵌套的序列类型,只能包含简单的原子类型,例如整数、浮点数或字符。
- 容器序列:可以嵌套,包含任何类型的对象,甚至是容器类型自身。
-
大杂烩列表:
- 如果列表中的项不可比较,就不能排序。
- 如果元组中的每一项都是一个字段,那么每个字段就可以具有不同的类型。
-
聪明的
key:- 只需要定义一个单参数函数,通过它获取或计算用于排序对象的标准即可。
- 高效:key指定的函数只在处理各项时调用一次,而双参数比较函数在每次需要通过排序算法比较两项时,都需要调用一次。
-
甲骨文、谷歌和Timbot阴谋论:
Oracle和list.sort使用的排序算法是Timsort,一种自适应算法,可根据数据的排序方法在插入排序法和归并排序法之间切换。Timsort于2002年首次在CPython使用。Timsort由Tim Peters发明,称为Timbot。