百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

还能更快!教你几个Python加速运行技巧

off999 2024-10-19 07:20 31 浏览 0 评论

哈喽大家好,我是不秃头的。我相信大家总是会觉得Python运行代码较慢。Python 是一种脚本语言,相比 C/C++ 这样的编译语言,在效率和性能方面存在一些不足。但是,有很多时候,Python 效率并没有想象中的那么夸张。

本文对一些 Python 代码加速运行的技巧进行整理。

介绍

本文会介绍不少的 Python 代码加速运行的技巧。在深入代码优化细节之前,需要了解一些代码优化的基本原则。

第一个基本原则:不要过早优化

很多人一开始写代码就奔着性能优化的目标,“让正确的程序更快要比让快速的程序正确容易得多”。因此,优化的前提是代码能正常工作。过早地进行优化可能会忽视对总体性能指标的把握,在得到全局结果前不要主次颠倒。

第二个基本原则:权衡优化的代价

优化是有代价的,想解决所有性能的问题是几乎不可能的。通常面临的选择是时间换空间或空间换时间。另外,开发代价也需要考虑。

第三个原则:不要优化那些无关紧要的部分

如果对代码的每一部分都去优化,这些修改会使代码难以阅读和理解。如果你的代码运行速度很慢,首先要找到代码运行慢的位置,通常是内部循环,专注于运行慢的地方进行优化。在其他地方,一点时间上的损失没有什么影响。

1. 避免全局变量

# 不推荐写法。代码耗时:26.8秒
import math

size = 10000
for x in range(size):
    for y in range(size):
        z = math.sqrt(x) + math.sqrt(y

许多程序员刚开始会用 Python 语言写一些简单的脚本,当编写脚本时,通常习惯了直接将其写为全局变量,例如上面的代码。但是,由于全局变量和局部变量实现方式不同,定义在全局范围内的代码运行速度会比定义在函数中的慢不少。通过将脚本语句放入到函数中,通常可带来 15% - 30% 的速度提升。

# 推荐写法。代码耗时:20.6秒
import math

def main():  # 定义到函数中,以减少全部变量使用
    size = 10000
    for x in range(size):
        for y in range(size):
            z = math.sqrt(x) + math.sqrt(y)

main()

2. 类内属性访问

# 不推荐写法。代码耗时:10.4秒
import math
from typing import List

class DemoClass:
    def __init__(self, value: int):
        self._value = value
    
    def computeSqrt(self, size: int) -> List[float]:
        result = []
        append = result.append
        sqrt = math.sqrt
        for _ in range(size):
            append(sqrt(self._value))
        return result

def main():
    size = 10000
    for _ in range(size):
        demo_instance = DemoClass(size)
        result = demo_instance.computeSqrt(size)

main()

避免.的原则也适用于类内属性,访问self._value的速度会比访问一个局部变量更慢一些。通过将需要频繁访问的类内属性赋值给一个局部变量,可以提升代码运行速度。

# 推荐写法。代码耗时:8.0秒
import math
from typing import List

class DemoClass:
    def __init__(self, value: int):
        self._value = value
    
    def computeSqrt(self, size: int) -> List[float]:
        result = []
        append = result.append
        sqrt = math.sqrt
        value = self._value
        for _ in range(size):
            append(sqrt(value))  # 避免 self._value 的使用
        return result

def main():
    size = 10000
    for _ in range(size):
        demo_instance = DemoClass(size)
        demo_instance.computeSqrt(size)

main()

3. 避免数据复制

3.1 避免无意义的数据复制

# 不推荐写法,代码耗时:6.5秒
def main():
    size = 10000
    for _ in range(size):
        value = range(size)
        value_list = [x for x in value]
        square_list = [x * x for x in value_list]

main()

上面的代码中value_list完全没有必要,这会创建不必要的数据结构或复制。

# 推荐写法,代码耗时:4.8秒
def main():
    size = 10000
    for _ in range(size):
        value = range(size)
        square_list = [x * x for x in value]  # 避免无意义的复制

main()

另外一种情况是对 Python 的数据共享机制过于偏执,并没有很好地理解或信任 Python 的内存模型,滥用 copy.deepcopy()之类的函数。通常在这些代码中是可以去掉复制操作的。

3.2 交换值时不使用中间变量

# 不推荐写法,代码耗时:0.07秒
def main():
    size = 1000000
    for _ in range(size):
        a = 3
        b = 5
        temp = a
        a = b
        b = temp

main()

上面的代码在交换值时创建了一个临时变量temp,如果不借助中间变量,代码更为简洁、且运行速度更快。

# 推荐写法,代码耗时:0.06秒
def main():
    size = 1000000
    for _ in range(size):
        a = 3
        b = 5
        a, b = b, a  # 不借助中间变量

main()

4. 避免不必要的抽象

# 不推荐写法,代码耗时:0.55秒
class DemoClass:
    def __init__(self, value: int):
        self.value = value

    @property
    def value(self) -> int:
        return self._value

    @value.setter
    def value(self, x: int):
        self._value = x

def main():
    size = 1000000
    for i in range(size):
        demo_instance = DemoClass(size)
        value = demo_instance.value
        demo_instance.value = i

main()

任何时候当你使用额外的处理层(比如装饰器、属性访问、描述器)去包装代码时,都会让代码变慢。大部分情况下,需要重新进行审视使用属性访问器的定义是否有必要,使用getter/setter函数对属性进行访问通常是 C/C++ 程序员遗留下来的代码风格。如果真的没有必要,就使用简单属性。

# 推荐写法,代码耗时:0.33秒
class DemoClass:
    def __init__(self, value: int):
        self.value = value  # 避免不必要的属性访问器

def main():
    size = 1000000
    for i in range(size):
        demo_instance = DemoClass(size)
        value = demo_instance.value
        demo_instance.value = i

main()

5. 利用if条件的短路特性

# 不推荐写法,代码耗时:0.05秒
from typing import List

def concatString(string_list: List[str]) -> str:
    abbreviations = {'cf.', 'e.g.', 'ex.', 'etc.', 'flg.', 'i.e.', 'Mr.', 'vs.'}
    abbr_count = 0
    result = ''
    for str_i in string_list:
        if str_i in abbreviations:
            result += str_i
    return result

def main():
    for _ in range(10000):
        string_list = ['Mr.', 'Hat', 'is', 'Chasing', 'the', 'black', 'cat', '.']
        result = concatString(string_list)

main()

if 条件的短路特性是指对if a and b这样的语句, 当a为False时将直接返回,不再计算b;对于if a or b这样的语句,当a为True时将直接返回,不再计算b。因此, 为了节约运行时间,对于or语句,应该将值为True可能性比较高的变量写在or前,而and应该推后。

# 推荐写法,代码耗时:0.03秒
from typing import List

def concatString(string_list: List[str]) -> str:
    abbreviations = {'cf.', 'e.g.', 'ex.', 'etc.', 'flg.', 'i.e.', 'Mr.', 'vs.'}
    abbr_count = 0
    result = ''
    for str_i in string_list:
        if str_i[-1] == '.' and str_i in abbreviations:  # 利用 if 条件的短路特性
            result += str_i
    return result

def main():
    for _ in range(10000):
        string_list = ['Mr.', 'Hat', 'is', 'Chasing', 'the', 'black', 'cat', '.']
        result = concatString(string_list)

main()

6. 用for循环代替while循环

# 不推荐写法。代码耗时:6.7秒
def computeSum(size: int) -> int:
    sum_ = 0
    i = 0
    while i < size:
        sum_ += i
        i += 1
    return sum_

def main():
    size = 10000
    for _ in range(size):
        sum_ = computeSum(size)

main()

Python 的for循环比while循环快不少。

# 推荐写法。代码耗时:4.3秒
def computeSum(size: int) -> int:
    sum_ = 0
    for i in range(size):  # for 循环代替 while 循环
        sum_ += i
    return sum_

def main():
    size = 10000
    for _ in range(size):
        sum_ = computeSum(size)

main()

7. 使用numba.jit

我们沿用上面介绍过的例子,在此基础上使用numba.jit。numba可以将 Python 函数 JIT 编译为机器码执行,大大提高代码运行速度。关于numba的更多信息见下面的主页:

http://numba.pydata.org/numba.pydata.org

# 推荐写法。代码耗时:0.62秒
import numba

@numba.jit
def computeSum(size: float) -> int:
    sum = 0
    for i in range(size):
        sum += i
    return sum

def main():
    size = 10000
    for _ in range(size):
        sum = computeSum(size)

main()


参考资料

  • https://zhuanlan.zhihu.com/p/143052860
  • David Beazley & Brian K. Jones. Python Cookbook, Third edition. O'Reilly Media, ISBN: 9781449340377, 2013.
  • 张颖 & 赖勇浩. 编写高质量代码:改善Python程序的91个建议. 机械工业出版社, ISBN: 9787111467045, 2014.

希望能对你的Python编写有帮助哦!

觉得对你有用的小伙伴点赞转发一下哦~

相关推荐

电脑刚启动就黑屏怎么办(电脑刚开机就黑屏怎么办)
  • 电脑刚启动就黑屏怎么办(电脑刚开机就黑屏怎么办)
  • 电脑刚启动就黑屏怎么办(电脑刚开机就黑屏怎么办)
  • 电脑刚启动就黑屏怎么办(电脑刚开机就黑屏怎么办)
  • 电脑刚启动就黑屏怎么办(电脑刚开机就黑屏怎么办)
网易用户中心官网(网易用户中心官网注册账号)

要登录网易个人中心的话,首先你网易要有自己的账户。你可以搜索一下网易的官方链接,打开以后先注册,注册成功了以后你就可以进到个人中心了,上面也可以做一些设置或修改你的密码之类的。然后你就可以多看一下,看...

windows defender怎么关闭win11

1.启用或禁用WindowsDefender的实时保护可以通过设置打开或者关闭某些模块(例如实时保护)的选项。第一步,右键点击开始菜单--设置或者按住WIN+I(大写的i)快捷键...

无法识别硬盘(无法识别硬盘怎么解决)

1.有可能可以修复2.因为硬盘无法识别可能是由于硬盘本身的故障或者连接线松动等原因导致的,可以尝试更换连接线或者使用一些数据恢复软件进行修复。但是如果硬盘本身的故障比较严重,可能需要专业的数据恢复...

win10固态硬盘如何分区(win10固态硬盘分区多大合适)

可以按照以下步骤进行分区。1.打开“此电脑”或“文件资源管理器”,右击“此电脑”,选择“管理”。2.在计算机管理窗口中,选择“磁盘管理”,找到你的固态硬盘。3.右击固态硬盘,选择“新建简单卷”。...

博图v19(博图v19安装过程中出错)

 西门子博途(TIAPortal)是用于工程设计和编程的软件平台,博途V19和V18是该平台的不同版本。它们在功能、性能和用户体验上有一定的区别。以下是一些主要区别:1.新功能和性能提升...

小米怎么关闭自动更新(如何关闭小米自动更新系统)

  方法/步骤分享:  1、首先找到自己手机上的设置选项。  2、找到设置之后我们看到下面有一个我的设备选项。  3、在我的设备下面有一个miui版本,点击这个版本号后面的箭头。  4、进入到系统更新...

隐藏的文件夹怎么才能显示出来

你可以打开我的电脑,随便找一个盘符点进去,然后点击左上角的组织选项,找到文件和文件夹选项,然后会弹出一个列表,找到选项显示所有文件和文件夹,把前面的勾打上就可以了。1.在资源管理器中,打开文件夹属性...

恢复出厂设置有什么影响吗(恢复出厂设置对有影响吗)

基本上没什么危害。恢复出厂设置是一次大容量的数据读写,清除,存储过程,相对一般日常使用来说,只是会对电脑的整个硬件硬盘形成一次重大磨损过程,大容量的数据读写,清除,存储,会加快硬盘的老化,但对电脑本身...

计算机电脑怎么设置密码(计算机在哪设置密码)

一、帐户    打开电脑,点击电脑左下角的开始菜单,在弹出的界面里找到“设置(齿轮形状)”。点击齿轮图标后,就会进入Windows10系统的设置界面,...

win10密钥激活码大全专业版免费破解版

1不存在永久激活密钥,但可以使用一些有效期长的密钥去激活Win10专业版。2Windows10的激活方式是基于数字权利,当你购买Windows10时,系统会将您电脑的硬件信息和购买记录绑定在一起...

免费动态壁纸2025(免费动态壁纸2023)

如果你想取消2023动态壁纸,可以按照以下步骤操作:首先,在桌面上右键点击空白区域,选择“个性化”;接着,在弹出的窗口中选择“背景”,找到“壁纸”选项,选择“图片”;最后,在“壁纸”选项下面找到“浏览...

360游戏中心手机网页版(360网页游戏平台官网)

360游戏大厅的登录方法:首先,需要在应用程序中搜索并安装360手机卫士应用程序,然后打开应用程序并点击“账号与安全”选项,在页面中选择“360账号登录”并输入账号密码即可成功登录360帐号,然后点击...

重装系统怎样保留原来的软件

1、只装系统到C盘,只需要格式化C盘即可,其他盘的文件都不会清空。2、硬盘整个格式化,所有盘都需要重新分区,所有的数据都会丢失。另外,应用程序在重装系统后肯定是运行不了了,需要重装应用程序。你装的系统...

由于英语(由于生病,他不能来参加会议英语)
由于英语(由于生病,他不能来参加会议英语)

“因为”的英文短语:owingto、becauseof;“结果”的英文短语:intheendbecause读法英[b??k?z]美[b??k??z]conj.因为短语:1、justbecause正因为2、me...

2025-12-26 07:03 off999

取消回复欢迎 发表评论: