Skip to content

高效Python90条之第7条 尽量用enumerate取代range

要点:

  • enumerate函数可以用简洁的代码迭代iterator,而且可以指出当前这轮循环的序号。
  • 不要先通过range指定下标的取值范围,然后用下标去访问序列,而是应该直接用enumerate函数迭代。
  • 可以通过enumerate的第二个参数指定起始序号(默认为0)。

Python内置的range函数适合用来迭代一系列整数。

from random import randint

random_bits = 0
for i in range(32):
    if randint(0, 1):
        random_bits |= 1 << i  # 运算符|是二进制OR操作

print(bin(random_bits))
# 0b1101110010100110001001111011011

如果要迭代的是某种数据结构,例如字符串列表,那么可以直接在这个序列上面迭代,不需要通过range

flavor_list = ["vanilla", "chocolate", "pecan", "strawberry"]

for flavor in flavor_list:
    print(f"{flavor} is delicious")

# vanilla is delicious
# chocolate is delicious
# pecan is delicious
# strawberry is delicious要点:

* enumerate函数可以用简洁的代码迭代iterator而且可以指出当前这轮循环的序号
* 不要先通过range指定下标的取值范围然后用下标去访问序列而是应该直接用enumerate函数迭代
* 可以通过enumerate的第二个参数指定起始序号默认为0)。

通过传统的range方法,给每种口味添加序列号。但步骤有些太多,先得知道列表的长度,然后要根据列表长度构造取值范围,用其中的每个整数做下标,分别访问列表里的对应元素。

flavor_list = ["vanilla", "chocolate", "pecan", "strawberry"]

for i in range(len(flavor_list)):
    flavor = flavor_list[i]
    print(f"{i + 1}: {flavor}")

# 1: vanilla
# 2: chocolate
# 3: pecan
# 4: strawberry

Python的内置的函数enumerate,能够把任何一种迭代器(iterator)封装成惰性生成器(lazy generator,参见Rule30)。 这样每次循环的时候,它只需要从iterator里面获取下一个值就行了,同时还会给出本轮循环的序号,即生成器每次产生的一对输出值。

下面通过内置的next函数手动推进enumerate所返回的这个iterator,来演示enumerate

flavor_list = ["vanilla", "chocolate", "pecan", "strawberry"]

it = enumerate(flavor_list)

print(next(it))  # (0, 'vanilla')
print(next(it))  # (1, 'chocolate')
print(next(it))  # (2, 'pecan')
print(next(it))  # (3, 'strawberry')
print(next(it))  # Error: StopIteration

enumerate输出的每一对数据,都可以拆分(unpacking)到for语句的那两个变量里面,这样会让代码更加清晰。

flavor_list = ["vanilla", "chocolate", "pecan", "strawberry"]

for i, flavor in enumerate(flavor_list):
    print(f"{i + 1}: {flavor}")
# 1: vanilla
# 2: chocolate
# 3: pecan
# 4: strawberry

for i, flavor in enumerate(flavor_list, 1):
    print(f"{i}: {flavor}")
# 1: vanilla
# 2: chocolate
# 3: pecan
# 4: strawberry

enumerate也可以用在处理二维数组上。

data = [
    [1, 1, 1],
    [2, 2, 2],
    [3, 3, 3],
    [4, 4, 4],
    [5, 5, 5],
    [10, 10, 10],
    [20, 20, 20],
    [30, 30, 30],
    [40, 40, 40],
    [50, 50, 50],
]

for i, row in enumerate(data):
    if i + 5 < len(data):
        # 对第 i 行和第 i+5 行进行加法运算
        result = [a + b * 10 for a, b in zip(row, data[i + 5])]
        print(f"Row {i} + Row {i+5} * 5 = {result}")