Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Python 实现循环的最快方式

Python 实现循环的最快方式

原创
作者头像
我叫什么好
发布于 2021-12-25 01:27:45
发布于 2021-12-25 01:27:45
1.7K00
代码可运行
举报
文章被收录于专栏:Python1.0Python1.0
运行总次数:0
代码可运行

众所周知,Python 不是一种执行效率较高的语言。此外在任何语言中,循环都是一种非常消耗时间的操作。假如任意一种简单的单步操作耗费的时间为 1 个单位,将此操作重复执行上万次,最终耗费的时间也将增长上万倍。

whilefor 是 Python 中常用的两种实现循环的关键字,它们的运行效率实际上是有差距的。比如下面的测试代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import timeit
​
​
def while_loop(n=100_000_000):
    i = 0
    s = 0
    while i < n:
        s += i
        i += 1
    return s
​
​
def for_loop(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
    return s
​
​
def main():
    print('while loop\t\t', timeit.timeit(while_loop, number=1))
    print('for loop\t\t', timeit.timeit(for_loop, number=1))
​
​
if __name__ == '__main__':
    main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354

这是一个简单的求和操作,计算从 1 到 n 之间所有自然数的总和。可以看到 for 循环相比 while 要快 1.5 秒。

其中的差距主要在于两者的机制不同。

在每次循环中,while 实际上比 for 多执行了两步操作:边界检查和变量 i 的自增。即每进行一次循环,while 都会做一次边界检查 (while i < n)和自增计算(i +=1)。这两步操作都是显式的纯 Python 代码。

for 循环不需要执行边界检查和自增操作,没有增加显式的 Python 代码(纯 Python 代码效率低于底层的 C 代码)。当循环的次数足够多,就出现了明显的效率差距。

可以再增加两个函数,在 for 循环中加上不必要的边界检查和自增计算:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import timeit
​
​
def while_loop(n=100_000_000):
    i = 0
    s = 0
    while i < n:
        s += i
        i += 1
    return s
​
​
def for_loop(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
    return s
​
​
def for_loop_with_inc(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
        i += 1
    return s
​
​
def for_loop_with_test(n=100_000_000):
    s = 0
    for i in range(n):
        if i < n:
            pass
        s += i
    return s
​
​
def main():
    print('while loop\t\t', timeit.timeit(while_loop, number=1))
    print('for loop\t\t', timeit.timeit(for_loop, number=1))
    print('for loop with increment\t\t',
          timeit.timeit(for_loop_with_inc, number=1))
    print('for loop with test\t\t', timeit.timeit(for_loop_with_test, number=1))
​
​
if __name__ == '__main__':
    main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => for loop with increment          4.602369500091299
# => for loop with test               4.18337869993411

可以看出,增加的边界检查和自增操作确实大大影响了 for 循环的执行效率。

前面提到过,Python 底层的解释器和内置函数是用 C 语言实现的。而 C 语言的执行效率远大于 Python。

对于上面的求等差数列之和的操作,借助于 Python 内置的 sum 函数,可以获得远大于 forwhile 循环的执行效率。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import timeit
​
​
def while_loop(n=100_000_000):
    i = 0
    s = 0
    while i < n:
        s += i
        i += 1
    return s
​
​
def for_loop(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
    return s
​
​
def sum_range(n=100_000_000):
    return sum(range(n))
​
​
def main():
    print('while loop\t\t', timeit.timeit(while_loop, number=1))
    print('for loop\t\t', timeit.timeit(for_loop, number=1))
    print('sum range\t\t', timeit.timeit(sum_range, number=1))
​
​
if __name__ == '__main__':
    main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => sum range                0.8658821999561042

可以看到,使用内置函数 sum 替代循环之后,代码的执行效率实现了成倍的增长。

内置函数 sum 的累加操作实际上也是一种循环,但它由 C 语言实现,而 for 循环中的求和操作是由纯 Python 代码 s += i 实现的。C > Python。

再拓展一下思维。小时候都听说过童年高斯巧妙地计算 1 到 100 之和的故事。1…100 之和等于 (1 + 100) * 50。这个计算方法同样可以应用到上面的求和操作中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import timeit
​
​
def while_loop(n=100_000_000):
    i = 0
    s = 0
    while i < n:
        s += i
        i += 1
    return s
​
​
def for_loop(n=100_000_000):
    s = 0
    for i in range(n):
        s += i
    return s
​
​
def sum_range(n=100_000_000):
    return sum(range(n))
​
​
def math_sum(n=100_000_000):
    return (n * (n - 1)) // 2
​
​
def main():
    print('while loop\t\t', timeit.timeit(while_loop, number=1))
    print('for loop\t\t', timeit.timeit(for_loop, number=1))
    print('sum range\t\t', timeit.timeit(sum_range, number=1))
    print('math sum\t\t', timeit.timeit(math_sum, number=1))
​
​
if __name__ == '__main__':
    main()
# => while loop               4.718853999860585
# => for loop                 3.211570399813354
# => sum range                0.8658821999561042
# => math sum                 2.400018274784088e-06

最终 math sum 的执行时间约为 2.4e-6,缩短了上百万倍。这里的思路就是,既然循环的效率低,一段代码要重复执行上亿次。

索性直接不要循环,通过数学公式,把上亿次的循环操作变成只有一步操作。效率自然得到了空前的加强。

最后的结论(有点谜语人):

实现循环的最快方式—— —— ——就是不用循环

对于 Python 而言,则尽可能地使用内置函数,将循环中的纯 Python 代码降到最低。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python 中最快的循环姿势
大家好,我是 somenzz,今天我们来研究一下 Python 中最快的循环方法。
somenzz
2021/11/04
6380
时间都去哪儿了之Python程序测试与优化
有时候我们需要知道自己的代码运行了多久,time模块的方法提供了这个功能,但是不很准确,例如下面的代码,当循环次数小的时候得到的结果为0,显然这是不可能的。 import time def test(v): """Stupid test function""" return sum(v) if __name__ == '__main__': starttime = time.time() for i in range(10000): test(range(100))
Python小屋屋主
2018/04/16
5350
流畅的python
流畅的python中有很多奇技淫巧,整本书都在强调如何最大限度地利用Python 标准库。介绍了很多python的不常用的数据类型、操作、库等,对于入门python后想要提升对python的认识应该有帮助。目前读一遍记录了一些有共鸣的操作:
py3study
2020/01/03
2.4K0
Python | 优雅的列表推导式
采用 for 循环,加条件判断,很轻松就可以实现。但有没有更简洁的实现方式?列表推导式(List Comprehension)。对比看看两者的效果。
PyStaData
2020/07/21
6140
Python 进阶指南(编程轻松进阶):十三、性能测量和大 O 算法分析
有时候花时间学习如何更快地制作脚本是明智的。但是在我们知道如何测量程序速度之前,我们无法知道我们的改变是否提高了程序的速度。这就是 Python 的timeit和cProfile模块的用武之地。这些模块不仅测量代码运行的速度,还创建了一个档案,显示代码的哪些部分已经很快了,哪些部分我们还可以改进。
ApacheCN_飞龙
2023/04/09
5550
Python 进阶指南(编程轻松进阶):十三、性能测量和大 O 算法分析
python 之 内置函数大全[通俗易懂]
  戳:https://docs.python.org/2/library/functions.html
全栈程序员站长
2022/09/08
4140
python 之 内置函数大全[通俗易懂]
Python 代码优化技巧(一)
对于and,应该把满足条件少的放在前面,这样当对于大量判断时, 满足条件少的情况直接回导致其后其他表达式不会计算从而节约时间(因为 False and True 还是 False)
py3study
2020/01/03
4400
Python列表解析式到底该怎么用?
Python 是一种极其多样化和强大的编程语言!当需要解决一个问题时,它有着不同的方法。在本文中,将会展示列表解析式(List Comprehension)。我们将讨论如何使用它?什么时候该或不该使用它?
吾非同
2022/05/25
2.3K0
​Python统计代码耗时的几种方法
本文实例讲述了Python中统计代码片段、函数运行耗时的几种方法,分享给大家,仅供参考。
吾非同
2021/04/21
17.7K0
​Python统计代码耗时的几种方法
timeit python_如何使用timeit来分析Python代码
通过设计,Python将便利性,可读性和易用性置于性能之上。 但这并不意味着您应该适应缓慢的Python代码。 您可能需要采取一些措施来加快速度。
用户7886150
2020/12/23
1K0
python中程序运行计时的三种方式
下面这段程序截取自Python High Performance Programming(个人觉得这本书还不错,虽然有点零碎。因为我做数据分析比较多,有时候数据量大了确实也需要考虑代码优化。当然,如果数据量太大,我应该还是会毫不犹豫地用SAS。)
py3study
2020/01/06
3.4K0
向量化操作简介和Pandas、Numpy示例
Pandas是一种流行的用于数据操作的Python库,它提供了一种称为“向量化”的强大技术可以有效地将操作应用于整个列或数据系列,从而消除了显式循环的需要。在本文中,我们将探讨什么是向量化,以及它如何简化数据分析任务。
deephub
2023/10/23
9030
向量化操作简介和Pandas、Numpy示例
Python | Python 新手不可错过的 Python 知识合集
来源:https://segmentfault.com/a/1190000018737045
咸鱼学Python
2020/04/08
1.5K0
深入解析 Python 中的上下文管理器
但是,timeit.timeit函数仅接受字符串,如果要管理比较复杂的函数时会有局限性。以下示例向您展示如何使用timeit模块运行和管理函数。
代码医生工作室
2020/05/08
6370
Python3内置模块使用
(1)内置模块一览表 描述:模块是一个包含所有您定义的函数和变量的文件其后缀名为.py,模块可以被失败引入的以使用该模块中的函数等功能。
全栈工程师修炼指南
2020/10/23
1.8K0
Python3内置模块使用
开源图书《Python完全自学教程》7.5递归
在7.1.2节编写斐波那契数列函数的时候,使用了 Python 中的递归(Recursion)。固然 Python 创始人对递归有个人的看法,此处还是要用单独一节专门给予介绍。等读者阅读完本节内容,也能理解之所以如此重视递归的原因了。
老齐
2022/07/06
1.2K0
开源图书《Python完全自学教程》7.5递归
超详解——Python 元组详解——小白篇
元组是Python中的一种序列类型,使用圆括号 () 表示。元组可以包含任意类型的元素,包括数字、字符串、列表、甚至其他元组。元组的不可变性使得它们在某些场景下非常有用,例如作为函数的返回值,或者作为字典的键。
小李很执着
2024/06/15
3320
温故而知新:11 个编程小技巧,使用起来更省心
正在学 Python 的你并不孤单,有我在这里陪着你每天学习一个 Python 小技术,今天我为初学者整理了 11 个编程小技巧,使用起来非常省心,相信你看完定会有所收获。
程序员小二
2021/12/22
1960
温故而知新:11 个编程小技巧,使用起来更省心
11 个编程小技巧,使用起来更省心
正在学 Python 的你并不孤单,有我在这里陪着你每天学习一个 Python 小技术,你可以加我微信「somenzz」相互交流。今天我为初学者整理了 11 个编程小技巧,使用起来非常省心,相信你看完定会有所收获。
somenzz
2021/10/08
2900
07 Python序列类型深入解析:从range到元组
range()是Python中一个非常实用的内置函数,用于生成一个数字序列。它的特点是内存效率高,因为它不会立即生成所有数字,而是在需要时才生成(惰性求值)。
全栈若城
2025/02/28
810
07 Python序列类型深入解析:从range到元组
相关推荐
Python 中最快的循环姿势
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验