0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

优化代码,加速Python运行的八大方法

如意 来源:百家号 作者:读芯术 2020-07-01 09:50 次阅读

Python有时用起来确实很慢,我敢打赌你肯定抱怨过这一点,尤其是那些用惯了C,C ++或Java的人。

但其实很多时候,Python的效率并没有达到它应有的速度,有一些让它马达开足的小技巧,一起来学习吧!

1.避免使用全局变量

import mathsize = 10000

for x in range(size):

for y in range(size):

z = math.sqrt(x) + math.sqrt(y)

许多程序员一开始都会用Python语言编写一些简单的脚本。编写脚本时,通常直接使用全局变量,就像上面这段代码。

但由于全局变量和局部变量的实现方式不同,全局变量中定义的代码要比在函数中定义的函数运行起来慢得多。把脚本语句放入函数中,通常运行速度可提高15%-30%。如下所示:

import mathdef main():

size = 10000

for x in range(size):

for y in range(size):

z = math.sqrt(x) +math.sqrt(y)main()

2.避免数据重复

避免无意义的数据复制

def main():

size = 10000

for _ in range(size):

value = range(size)

value_list = [x for x in value]

square_list = [x * x for x invalue_list]main()

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

def main():

size = 10000

for _ in range(size):

value = range(size)

square_list = [x * x for x invalue]main()

另一个原因在于Python的数据共享机制过于偏执,没有很好理解或信任内存模型,例如滥用copy.deepcopy()函数。我们可以删除此类代码中的复制操作。

交换值时无需使用中间变量

def main():

size = 1000000

for _ in range(size):

a = 3

b = 5

temp = a

a = b

b = tempmain()

上述代码在交换值时创建了一个临时变量temp。如果没有中间变量,代码会更加简洁,运行速度也更快。

def main():

size = 1000000

for _ in range(size):

a = 3

b = 5

a, b = b, amain()

使用字符串联方法join ,而不是‘+’

import string

from typing import Listdef concatString(string_list: List[str]) -》 str:

result = ‘’

for str_i in string_list:

result += str_i

return resultdef main():

string_list =list(string.ascii_letters * 100)

for _ in range(10000):

result =concatString(string_list)main()

另一要点是a+b对字符串进行拼接,由于在Python中字符串是不可变的对象,所以实际上a和b分别复制到了应用程序的新内存空间中。

因此,如果拼接n个字符串会产生“ n-1”个中间结果,则每个字符串都会产生应用和复制内存所需的中间结果,从而严重影响操作效率。

在使用join()串联字符串时,首先计算需要应用的总内存空间,然后立即申请所需的内存,再把每个字符串元素复制到内存中。

import string

from typing import Listdef concatString(string_list: List[str]) -》 str:

return ‘’.join(string_list)defmain():

string_list = list(string.ascii_letters* 100)

for _ in range(10000):

result =concatString(string_list)main()

3.避免使用以下函数属性

避免访问模块和函数属性

import mathdef computeSqrt(size:int):

result = []

for i in range(size):

result.append(math.sqrt(i))

return resultdef main():

size = 10000

for _ in range(size):

result = computeSqrt(size)main()

use(属性访问运算符)会触发特定方法,例如getattribute()和getattr(),这些方法将执行字典操作,会产生额外的时间消耗。

通过使用import语句,可以消除属性访问:

from math import sqrtdefcomputeSqrt(size: int):

result = []

for i in range(size):

result.append(sqrt(i))

return resultdef main():

size = 10000

for _ in range(size):

result = computeSqrt(size)main()

前文中我们讨论了局部变量可以比全局变量实现更快查找,对于经常访问的变量(如sqrt),可以通过更改为局部变量以加快操作速度。

import mathdef computeSqrt(size:int):

result = []

sqrt = math.sqrt

for i in range(size):

result.append(sqrt(i))

return resultdef main():

size = 10000

for _ in range(size):

result = computeSqrt(size)main()

避免类属性访问

import math

from typing import Listclass 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 resultdef main():

size = 10000

for _ in range(size):

demo_instance = DemoClass(size)

result =demo_instance.computeSqrt(size)main()

避免的原理也适用于类的属性,并且访问self._value的速度要比访问局部变量的速度要慢。通过把需要频繁访问的类属性分配给局部变量,可以提高代码执行速度。

import math

from typing import Listclass 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))

return resultdef main():

size = 10000

for _ in range(size):

demo_instance = DemoClass(size)

demo_instance.computeSqrt(size)main()

4.避免不必要的抽象

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 = xdef main():

size = 1000000

for i in range(size):

demo_instance = DemoClass(size)

value = demo_instance.value

demo_instance.value = imain()

每当使用其他处理层(例如装饰器、属性访问、描述符)封装代码时,代码运行的速度也会变慢。在大多数情况下,重新检查是否有必要使用属性访问器定义是很有必要的。

使用getter/setter函数访问属性通常是被C/C++程序员遗忘的一种编码样式。如果确实没有必要,就使用简单属性就好。

class DemoClass:

def __init__(self, value: int):

self.value = valuedef main():

size = 1000000

for i in range(size):

demo_instance = DemoClass(size)

value = demo_instance.value

demo_instance.value = imain()

5.选择合适的数据结构

众所周知,列表是Python中的动态数组。当预分配的内存空间用完时,会预分配一定的内存空间,然后继续向其中添加元素。然后复制之前的所有原始元素,形成一个新的内存空间,在插入新元素之前销毁先前的内存空间。

因此,如果频繁添加或删除,或者添加或删除的元素数量太大,列表的效率就会变低,目前最好使用collections.deque。

此双端队列具有堆栈和队列的特性,并且可以在两端以O(1)复杂度执行插入和删除操作。

列表搜索操作非常耗时。当需要频繁查找某些元素或按顺序频繁访问这些元素时,保持列表 对象有序的情况下使用二分法,使用二进制搜索以提高搜索效率,但二进制搜索仅适用于有序元素。

另一个常见的要求是找到最小值或最大值。此时,可以使用heapq模块列出转换为堆的列表,因此获取最小值的时间复杂度为O(1)。

6.循环优化

使用 for 循环代替while 循环

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循环快得多。

def computeSum(size: int) -》int:

sum_ = 0

for i in range(size):

sum_ += i

return sum_def main():

size = 10000

for _ in range(size):

sum_ = computeSum(size)main()

使用隐式for循环,而不是显式for循环

对于上面的示例,可以进一步使用隐式for循环替换显式for循环

def computeSum(size: int) -》int:

return sum(range(size))def main():

size = 10000

for _ in range(size):

sum = computeSum(size)main()

减少内部循环的计算

from math import sqrtdef main():

size = 10000 for x in range(size):

for y in range(size):

z = sqrt(x) + sqrt(y)main()

在上述for循环中的代码sqrt(x)中,在训练期间每次都需要进行重新计算,这会增加时间消耗。

import mathdef main():

size = 10000for x in range(size):

sqrt_x = sqrt(x)

for y in range(size):

z = sqrt_x + sqrt(y)main()

7.使用 numba.jit

继续遵循上述示例,并在此基础上使用numba.jit。Python函数JIT可以编译为机器代码用以执行,这能大大提高了代码执行速度。

import numba@numba.jit

def computeSum(size: float) -》 int:

sum = 0

for i in range(size):

sum += i

return sumdef main():

size = 10000

for _ in range(size):

sum = computeSum(size)main()

8.代码优化原则

上文已经介绍了许多加速Python代码的技术。在编写代码的过程中,我们需要了解代码优化的一些基本原理,这可是“实用知识”。

第一个基本原则就是不要过早优化代码。

许多人一开始编写代码时就致力于性能优化,“加快正确程序的速度要比确保快速程序的正确运作容易得多。”优化代码的前提是确保代码可以正常工作。过早的优化可能会忽略对总体性能指标的掌握,并且在获得总体结果之前不要颠倒顺序。

第二个基本原则是权衡优化代码的成本。

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

第三个原则是不要优化无关紧要的部分。

如果优化代码的每个部分后,这些变更会让代码变得难以阅读和理解。如果代码运行缓慢,首先必须找到代码运行缓慢的位置(通常是内部循环),重点优化代码运行缓慢的地方。对于其他位置,时间的损失影响很小。

优化代码,让你的Python开足马力,快去实践一下吧!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编程
    +关注

    关注

    88

    文章

    3439

    浏览量

    92377
  • 优化
    +关注

    关注

    0

    文章

    220

    浏览量

    23714
  • python
    +关注

    关注

    51

    文章

    4674

    浏览量

    83464
收藏 人收藏

    评论

    相关推荐

    Python代码优化方法和准则

    Python开发代码简化除了采用规范化的编程规则之外,代码编写的逻辑性和对内置规则的掌握也对其有一定的影响,以下是Python3支持的用法,合理的利用可以极大的简化
    发表于 04-19 14:58

    解决传导干扰的八大对策分享

    容易解决,只要增加电源输入电路中 EMC 滤波器的节数,并适当调整每节滤波器的参数,基本上都能满足要求,下面讲解的八大对策,以解决对付传导干扰难题。
    发表于 10-22 14:23

    Python 加速的24个好方法分享

    时间 平凡方法 快捷方法(jupyter环境) 第4式,按行分析代码运行时间 平凡方法 快捷方法
    的头像 发表于 11-11 15:46 2206次阅读
    <b class='flag-5'>Python</b> <b class='flag-5'>加速</b>的24个好<b class='flag-5'>方法</b>分享

    Python 代码加速运行的的小技巧

    的技巧进行整理。 0. 代码优化原则本文会介绍不少的 Python 代码加速运行的技巧。在深入
    的头像 发表于 09-01 11:28 1501次阅读

    简述Python加速运行小窍门

    的技巧进行整理。 0. 代码优化原则 本文会介绍不少的 Python 代码加速运行的技巧。在深入
    的头像 发表于 10-20 15:28 2703次阅读

    使Python代码在BeagleBoard上运行

    电子发烧友网站提供《使Python代码在BeagleBoard上运行.zip》资料免费下载
    发表于 06-16 15:03 0次下载
    使<b class='flag-5'>Python</b><b class='flag-5'>代码</b>在BeagleBoard上<b class='flag-5'>运行</b>

    关于Python 加速工具的选单

      这篇文章会提供一些 优化代码的工具 。会让代码变得更简洁,或者更迅速。 当然这些并不能代替算法设计,但是还是能让 Python 加速很多
    的头像 发表于 07-07 11:19 228次阅读

    优化Python代码有哪些工具

    Python是一种强大的编程语言,但在面对复杂项目和紧迫的时间要求时,提高Python的使用效率变得至关重要。为此,以下是详细介绍十大工具,它们可以帮助您加速开发流程、提高编程体验并优化
    的头像 发表于 07-24 09:28 869次阅读

    python怎样运行代码

    讨论Python代码运行方式,包括解释器、交互式环境和命令行。 Python代码可以通过两种主要的方式
    的头像 发表于 11-22 10:31 637次阅读

    python如何换行而不运行代码

    Python中,换行是一种用来增加代码的可读性和组织性的方式。当你在编写Python代码时,换行通常用于分隔不同的代码行或块,使其更易于阅
    的头像 发表于 11-22 10:52 1255次阅读

    python运行一次自动再次运行

    使用循环语句是最简单的一种实现自动运行功能的方法。在Python中,可以使用while循环或for循环来实现。下面是一个使用while循环实现自动运行的例子: while True
    的头像 发表于 11-23 15:52 506次阅读

    python代码写完后点哪个运行

    当你完成了编写Python代码后,你可以选择多种方式来运行它。下面是几种常见的运行代码的方式: Pyth
    的头像 发表于 11-24 09:28 1166次阅读

    python如何换行而不运行代码

    和可读性。 在Python中,可以使用两个主要的方法进行换行:使用反斜杠()和使用圆括号(())。 第一种方式是使用反斜杠()来表示换行。在Python中,反斜杠是一个转义字符,它可以用于将一行
    的头像 发表于 11-24 09:50 1341次阅读

    运行Python程序的几种常见方法

    : 使用Python解释器 Python解释器是运行Python程序的基本工具。在命令行中输入 python 命令,即可启动解释器。然后输入
    的头像 发表于 11-28 15:32 468次阅读

    python软件怎么运行代码

    Python是一种高级编程语言,它被广泛用于开发各种类型的应用程序,从简单的脚本到复杂的网络应用和机器学习模型。要运行Python代码,您需要一个P
    的头像 发表于 11-28 16:02 533次阅读