0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

優(yōu)化代碼,加速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語言編寫一些簡單的腳本。編寫腳本時,通常直接使用全局變量,就像上面這段代碼。

但由于全局變量和局部變量的實現(xiàn)方式不同,全局變量中定義的代碼要比在函數(shù)中定義的函數(shù)運行起來慢得多。把腳本語句放入函數(shù)中,通常運行速度可提高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.避免數(shù)據(jù)重復

避免無意義的數(shù)據(jù)復制

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完全沒有必要,這會創(chuàng)建不必要的數(shù)據(jù)結構或復制。

def main():

size = 10000

for _ in range(size):

value = range(size)

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

另一個原因在于Python的數(shù)據(jù)共享機制過于偏執(zhí),沒有很好理解或信任內存模型,例如濫用copy.deepcopy()函數(shù)。我們可以刪除此類代碼中的復制操作。

交換值時無需使用中間變量

def main():

size = 1000000

for _ in range(size):

a = 3

b = 5

temp = a

a = b

b = tempmain()

上述代碼在交換值時創(chuàng)建了一個臨時變量temp。如果沒有中間變量,代碼會更加簡潔,運行速度也更快。

def main():

size = 1000000

for _ in range(size):

a = 3

b = 5

a, b = b, amain()

使用字符串聯(lián)方法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個字符串會產(chǎn)生“ n-1”個中間結果,則每個字符串都會產(chǎn)生應用和復制內存所需的中間結果,從而嚴重影響操作效率。

在使用join()串聯(lián)字符串時,首先計算需要應用的總內存空間,然后立即申請所需的內存,再把每個字符串元素復制到內存中。

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.避免使用以下函數(shù)屬性

避免訪問模塊和函數(shù)屬性

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(屬性訪問運算符)會觸發(fā)特定方法,例如getattribute()和getattr(),這些方法將執(zhí)行字典操作,會產(chǎn)生額外的時間消耗。

通過使用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()

前文中我們討論了局部變量可以比全局變量實現(xiàn)更快查找,對于經(jīng)常訪問的變量(如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的速度要比訪問局部變量的速度要慢。通過把需要頻繁訪問的類屬性分配給局部變量,可以提高代碼執(zhí)行速度。

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()

每當使用其他處理層(例如裝飾器、屬性訪問、描述符)封裝代碼時,代碼運行的速度也會變慢。在大多數(shù)情況下,重新檢查是否有必要使用屬性訪問器定義是很有必要的。

使用getter/setter函數(shù)訪問屬性通常是被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.選擇合適的數(shù)據(jù)結構

眾所周知,列表是Python中的動態(tài)數(shù)組。當預分配的內存空間用完時,會預分配一定的內存空間,然后繼續(xù)向其中添加元素。然后復制之前的所有原始元素,形成一個新的內存空間,在插入新元素之前銷毀先前的內存空間。

因此,如果頻繁添加或刪除,或者添加或刪除的元素數(shù)量太大,列表的效率就會變低,目前最好使用collections.deque。

此雙端隊列具有堆棧和隊列的特性,并且可以在兩端以O(1)復雜度執(zhí)行插入和刪除操作。

列表搜索操作非常耗時。當需要頻繁查找某些元素或按順序頻繁訪問這些元素時,保持列表 對象有序的情況下使用二分法,使用二進制搜索以提高搜索效率,但二進制搜索僅適用于有序元素。

另一個常見的要求是找到最小值或最大值。此時,可以使用heapq模塊列出轉換為堆的列表,因此獲取最小值的時間復雜度為O(1)。

6.循環(huán)優(yōu)化

使用 for 循環(huán)代替while 循環(huán)

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循環(huán)要比while循環(huán)快得多。

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循環(huán),而不是顯式for循環(huán)

對于上面的示例,可以進一步使用隱式for循環(huán)替換顯式for循環(huán)

def computeSum(size: int) -》int:

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

size = 10000

for _ in range(size):

sum = computeSum(size)main()

減少內部循環(huán)的計算

from math import sqrtdef main():

size = 10000 for x in range(size):

for y in range(size):

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

在上述for循環(huán)中的代碼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

繼續(xù)遵循上述示例,并在此基礎上使用numba.jit。Python函數(shù)JIT可以編譯為機器代碼用以執(zhí)行,這能大大提高了代碼執(zhí)行速度。

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.代碼優(yōu)化原則

上文已經(jīng)介紹了許多加速Python代碼的技術。在編寫代碼的過程中,我們需要了解代碼優(yōu)化的一些基本原理,這可是“實用知識”。

第一個基本原則就是不要過早優(yōu)化代碼。

許多人一開始編寫代碼時就致力于性能優(yōu)化,“加快正確程序的速度要比確??焖俪绦虻恼_運作容易得多?!眱?yōu)化代碼的前提是確保代碼可以正常工作。過早的優(yōu)化可能會忽略對總體性能指標的掌握,并且在獲得總體結果之前不要顛倒順序。

第二個基本原則是權衡優(yōu)化代碼的成本。

優(yōu)化代碼是有代價的,想要解決所有性能問題幾乎不可能。通常面臨的選擇是時間換空間或空間換時間,還需要考慮開發(fā)成本。

第三個原則是不要優(yōu)化無關緊要的部分。

如果優(yōu)化代碼的每個部分后,這些變更會讓代碼變得難以閱讀和理解。如果代碼運行緩慢,首先必須找到代碼運行緩慢的位置(通常是內部循環(huán)),重點優(yōu)化代碼運行緩慢的地方。對于其他位置,時間的損失影響很小。

優(yōu)化代碼,讓你的Python開足馬力,快去實踐一下吧!

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 編程
    +關注

    關注

    88

    文章

    3574

    瀏覽量

    93545
  • 優(yōu)化
    +關注

    關注

    0

    文章

    220

    瀏覽量

    23859
  • python
    +關注

    關注

    55

    文章

    4774

    瀏覽量

    84386
收藏 人收藏

    評論

    相關推薦

    Python代碼優(yōu)化方法和準則

    Python開發(fā)代碼簡化除了采用規(guī)范化的編程規(guī)則之外,代碼編寫的邏輯性和對內置規(guī)則的掌握也對其有一定的影響,以下是Python3支持的用法,合理的利用可以極大的簡化
    發(fā)表于 04-19 14:58

    解決傳導干擾的八大對策分享

    容易解決,只要增加電源輸入電路中 EMC 濾波器的節(jié)數(shù),并適當調整每節(jié)濾波器的參數(shù),基本上都能滿足要求,下面講解的八大對策,以解決對付傳導干擾難題。
    發(fā)表于 10-22 14:23

    Python 加速的24個好方法分享

    時間 平凡方法 快捷方法(jupyter環(huán)境) 第4式,按行分析代碼運行時間 平凡方法 快捷方法
    的頭像 發(fā)表于 11-11 15:46 ?2403次閱讀
    <b class='flag-5'>Python</b> <b class='flag-5'>加速</b>的24個好<b class='flag-5'>方法</b>分享

    Python 代碼加速運行的的小技巧

    的技巧進行整理。 0. 代碼優(yōu)化原則本文會介紹不少的 Python 代碼加速運行的技巧。在深入
    的頭像 發(fā)表于 09-01 11:28 ?1681次閱讀

    簡述Python加速運行小竅門

    的技巧進行整理。 0. 代碼優(yōu)化原則 本文會介紹不少的 Python 代碼加速運行的技巧。在深入
    的頭像 發(fā)表于 10-20 15:28 ?2836次閱讀

    使Python代碼在BeagleBoard上運行

    電子發(fā)燒友網(wǎng)站提供《使Python代碼在BeagleBoard上運行.zip》資料免費下載
    發(fā)表于 06-16 15:03 ?0次下載
    使<b class='flag-5'>Python</b><b class='flag-5'>代碼</b>在BeagleBoard上<b class='flag-5'>運行</b>

    關于Python 加速工具的選單

    ? 這篇文章會提供一些 優(yōu)化代碼的工具 。會讓代碼變得更簡潔,或者更迅速。 當然這些并不能代替算法設計,但是還是能讓 Python 加速很多
    的頭像 發(fā)表于 07-07 11:19 ?351次閱讀

    優(yōu)化Python代碼有哪些工具

    Python是一種強大的編程語言,但在面對復雜項目和緊迫的時間要求時,提高Python的使用效率變得至關重要。為此,以下是詳細介紹十大工具,它們可以幫助您加速開發(fā)流程、提高編程體驗并優(yōu)化
    的頭像 發(fā)表于 07-24 09:28 ?1313次閱讀

    python怎樣運行代碼

    討論Python代碼運行方式,包括解釋器、交互式環(huán)境和命令行。 Python代碼可以通過兩種主要的方式
    的頭像 發(fā)表于 11-22 10:31 ?1131次閱讀

    python如何查看運行過程

    常用的方法來查看Python程序的運行過程。 使用print語句輸出信息: 最簡單的方法是在代碼中使用print語句來輸出信息。我們可以在程
    的頭像 發(fā)表于 11-22 11:13 ?1841次閱讀

    python運行一次自動再次運行

    使用循環(huán)語句是最簡單的一種實現(xiàn)自動運行功能的方法。在Python中,可以使用while循環(huán)或for循環(huán)來實現(xiàn)。下面是一個使用while循環(huán)實現(xiàn)自動運行的例子: while True
    的頭像 發(fā)表于 11-23 15:52 ?1793次閱讀

    python代碼寫完后點哪個運行

    當你完成了編寫Python代碼后,你可以選擇多種方式來運行它。下面是幾種常見的運行代碼的方式: Pyth
    的頭像 發(fā)表于 11-24 09:28 ?4908次閱讀

    python如何換行而不運行代碼

    和可讀性。 在Python中,可以使用兩個主要的方法進行換行:使用反斜杠()和使用圓括號(())。 第一種方式是使用反斜杠()來表示換行。在Python中,反斜杠是一個轉義字符,它可以用于將一行
    的頭像 發(fā)表于 11-24 09:50 ?3048次閱讀

    運行Python程序的幾種常見方法

    : 使用Python解釋器 Python解釋器是運行Python程序的基本工具。在命令行中輸入 python 命令,即可啟動解釋器。然后輸入
    的頭像 發(fā)表于 11-28 15:32 ?2339次閱讀

    python軟件怎么運行代碼

    Python是一種高級編程語言,它被廣泛用于開發(fā)各種類型的應用程序,從簡單的腳本到復雜的網(wǎng)絡應用和機器學習模型。要運行Python代碼,您需要一個P
    的頭像 發(fā)表于 11-28 16:02 ?844次閱讀