欢迎光临
我们一直在努力

Effective Python 条款 7:告别range下标,善用enumerate与zip写出清爽代码

Effective Python 条款 7:告别range下标,善用enumerate与zip写出清爽代码

  • Bilibili 同步视频
  • 别再用 range + 下标遍历序列
  • enumerate:优雅获取循环序号的神器
    • 简单小案例:统计二进制位
  • 写在后面:即将登场的 zip 并行遍历
    • ✨最佳实践速记

写 Python 最怕什么?满屏的下标、生硬的range(len(list))循环,代码绕来绕去,读起来费脑子,改起来容易踩坑。很多新手刚上手时,习惯用其他语言的思维写循环,写出一堆不够 Pythonic 的代码。今天我们就聊聊迭代场景下两个宝藏内置函数:enumerate 和 zip,帮你把循环写得简洁又优雅✨。

Bilibili 同步视频

Effective Python 条款 7:告别range下标,善用enumerate与zip写出清爽代码

别再用 range + 下标遍历序列

很多刚从 C/C++ 转 Python 的开发者,遍历列表需要获取元素位置时,第一反应会写出下面这种代码:

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

# 不推荐的写法
for i in range(len(flavor_list)):
flavor = flavor_list[i]
print(f"{i + 1}: {flavor}")

这段代码逻辑没问题,可以正常输出口味和对应的排名。但它有几个很明显的短板:

  • 先要调用len()获取列表长度,再用range生成下标数字,步骤繁琐;

  • 循环拿到下标之后,还要再通过下标去取列表元素,多了一层索引访问;

  • 代码阅读成本高,一眼看过去分不清i到底代表什么,后续维护很容易因为下标偏移出现 bug。

  • 💡Python 的哲学:直接迭代容器本身,而不是迭代下标数字。 如果我们只需要元素,完全不需要下标,直接遍历列表就足够了:

    flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']
    for flavor in flavor_list:
    print(f"{flavor} is delicious")

    这种写法干净利落,不需要维护索引变量,可读性直接拉满。但现实开发里,我们经常既要拿到元素,又要拿到它的序号,这时候该怎么办?

    enumerate:优雅获取循环序号的神器

    Python 内置enumerate就是专门解决这个痛点的工具。 enumerate会接收一个迭代器,把它包装成一个惰性生成器。每次迭代的时候,会同时返回序号 + 当前元素这一组数据,配合 Python 的解包语法,一行 for 循环就能搞定两件事。

    我们可以手动调用next(),直观感受它的内部输出:

    flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']
    it = enumerate(flavor_list)
    print(next(it))
    print(next(it))

    输出:

    (0, 'vanilla')
    (1, 'chocolate')

    可以看到每一轮返回的是元组,第一个值是索引,第二个是列表元素。利用解包,直接写到 for 循环变量中:

    flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']
    for i, flavor in enumerate(flavor_list):
    print(f"{i + 1}: {flavor}")

    默认序号是从 0 开始,所以我们需要手动i+1做排名。

    但是!enumerate还藏了一个超好用的第二参数,可以直接指定起始编号,不用循环内部做数字偏移:

    flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry']
    # 第二个参数设置起始序号,直接从1开始计数
    for i, flavor in enumerate(flavor_list, 1):
    print(f"{i}: {flavor}")

    输出结果:

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

    ✅enumerate核心要点总结:

  • 它封装迭代器,惰性产出 (序号,元素),不会一次性把全部数据加载内存;

  • 优先替代range(len(xxx))这种下标遍历写法;

  • 第二个入参可以自定义起始序号,默认值为 0;

  • 配合解包语法,代码清爽,阅读者一眼看懂变量含义。

  • 📌小补充:对比性能,enumerate和range+下标总体性能差距很小,它的核心收益不是跑的更快,而是降低代码出错概率,提升可读性。写业务代码,可读性往往比几纳秒的性能更重要。

    简单小案例:统计二进制位

    再看一个小例子,用 range 遍历整数序列是合适的,因为我们本身就是要操作数字本身:

    from random import randint

    random_bits = 0
    for i in range(32):
    if randint(0, 1):
    random_bits |= 1 << i
    print(bin(random_bits))

    划重点:range适合迭代数字本身;而遍历容器、列表、字符串这类序列,需要序号优先选enumerate,不要强行用 range 做下标。

    写在后面:即将登场的 zip 并行遍历

    实际开发中,除了单列表带序号遍历,我们还经常遇到需要同时遍历两个甚至多个列表的场景,比如源列表生成派生列表,一一对应处理两组数据。 这时候就轮到zip出场,它可以把多个迭代器打包在一起同步迭代,避免手动维护下标去对齐两组数据,同样可以规避大量下标相关的 bug。

    ✨最佳实践速记

    场景推荐写法不推荐写法
    只取元素,不需要序号 for item in list for i in range(len(list))
    需要元素 + 序号 for i,item in enumerate(list, start=1) for i in range(len(list)): item = list[i]
    需要单纯生成数字序列 range(n) 不要强行构造列表来生成数字

    Pythonic 的代码,本质就是少写手动下标、多用语言内置工具和解包,让代码表达业务逻辑,而不是表达循环索引的细节。把繁琐的索引管理交给语言内置函数,我们专注业务逻辑本身。


    小结

  • 迭代序列优先直接遍历对象,不要无脑用 range 生成下标访问;

  • 需要序号时,优先使用enumerate,支持自定义起始序号;

  • range适合的场景是迭代数字,而不是用来拿容器下标;

  • 善用解包语法,让循环变量语义清晰,降低后续维护成本。

  • Effective Python 条款 6:告别range下标,善用enumerate与zip写出清爽代码

    后续我们继续拆解zip的用法,聊聊并行遍历多个迭代器的坑与技巧。

    赞(0)
    未经允许不得转载:171主机测评 » Effective Python 条款 7:告别range下标,善用enumerate与zip写出清爽代码
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址