Python代碼優(yōu)化指南:讓你代碼5X倍速
在編程語言的世界中,Python 作為一種應(yīng)用最為廣泛的語言之一,以其簡潔易讀的特點(diǎn)而聞名。由于其易讀的語法、面向?qū)ο蟮奶匦?、社區(qū)支持和豐富的庫資源,Python 在開發(fā)者中變得越來越受歡迎。它可以應(yīng)用于數(shù)據(jù)分析、人工智能、Web 開發(fā)、游戲開發(fā)等多個領(lǐng)域。
然而,與任何其他編程語言一樣,Python 的優(yōu)點(diǎn)也伴隨著一些問題。其中之一就是性能優(yōu)化。由于 Python 是一種解釋型語言,人們對其速度和性能存在一些擔(dān)憂。這就給了代碼優(yōu)化的用武之地。
什么是代碼優(yōu)化
- Python 是一種解釋型語言,這意味著它不能像 C 語言或 C++ 等編譯型語言那樣運(yùn)行得很快。然而,你可以利用某些技術(shù)和策略來優(yōu)化你的 Python 代碼,提高其性能。代碼優(yōu)化可以使你的代碼運(yùn)行更快、使用更少的資源和更順暢的執(zhí)行,從而提高其性能和效率。
- 本文描述了讓你的 Python 代碼運(yùn)行更快、更智能、更高效的藝術(shù)與方法。你將學(xué)習(xí)各種技術(shù)、策略和最佳實(shí)踐,幫助開發(fā)者充分發(fā)揮 Python 的潛力,同時克服其中的一些性能限制。
- 我們將使用 Python 的 timeit 模塊來對比傳統(tǒng) Python 代碼和優(yōu)化后的 Python 代碼的執(zhí)行時間。請注意,timeit 模塊默認(rèn)運(yùn)行函數(shù)一百萬次。言歸正傳,讓我們直接進(jìn)入優(yōu)化技術(shù)和策略。
一、使用推導(dǎo)式和生成器
在 Python 2.7 和 3.0 版本中,Python引入了推導(dǎo)式(comprehensions)等功能,包括列表推導(dǎo)式(List comprehension)、字典推導(dǎo)式(Dictionary comprehension)和緊密相關(guān)的集合推導(dǎo)式(Set comprehension)。這些功能讓我們可以更簡潔、更高效的生成列表、字典和集合。
>>> def do_1(): ... list_object = [] ... for i in range(100): ... list_object.append(i)
導(dǎo)入 Python 的內(nèi)置 timeit 模塊,看一下這個函數(shù)運(yùn)行多長時間:
>>> import timeit >>> t = timeit.Timer(setup='from __main__ import do_1', stmt='do_1()') >>> print(t.timeit()) 9.681053700041957
上面的輸出顯示,這個函數(shù)運(yùn)行大約需要9.68秒?,F(xiàn)在,使用推導(dǎo)式生成這個列表,看看需要多長時間:
>>> def do(): ... [i for i in range(100)] >>> t = timeit.Timer(setup='from __main__ import do', stmt='do()') >>> t.timeit() 7.292758799972944
從上面的代碼可以看出,這個函數(shù)的運(yùn)行時間約為 7.29 秒,而之前的函數(shù)(不使用推導(dǎo)式)需要 9.68 秒,兩者相差 2.39 秒。除了推導(dǎo)式更加簡潔易讀外,它還更快。這使得它成為生成列表和循環(huán)的首選方法。
二、避免字符串拼接
許多開發(fā)者喜歡使用+=運(yùn)算符對字符串進(jìn)行拼接。然而,在循環(huán)中這樣做可能會很慢,因?yàn)樵?python 中字符串是不可變。作為替代,我們可以使用 str.join() 方法進(jìn)行高效的字符串連接。下面我們就兩種方法的執(zhí)行時間進(jìn)行對比。
使用 += 運(yùn)算符進(jìn)行字符串連接并查看其執(zhí)行時間:
>>> def do(): ... obj = ["hello", "my", "name", "is", "Delight", "!"] ... s = "" ... for elem in obj: ... s += elem >>> import timeit >>> t = timeit.Timer(setup='from __main__ import do', stmt='do()') >>> t.timeit() 0.9870554000372067
該函數(shù)使用 += 運(yùn)算符實(shí)現(xiàn)字符串連接,大約需要 0.98 秒的時間來完成。
下面改用 join() 進(jìn)行有效的字符串連接:
>>> def do(): ... s = ["hello", "my", "name", "is", "Delight", "!"] ... "".join(s) >>> import timeit >>> t = timeit.Timer(setup='from __main__ import do', stmt='do()') >>> t.timeit() 0.38973289995919913
使用 join() 將函數(shù)的執(zhí)行時間從 0.98 秒減少到 0.38 秒,這使它成為更快和更可取的字符串連接方法。
三、循環(huán)
在 Python 中,for 循環(huán)是一種控制結(jié)構(gòu),允許您迭代一個序列中的項(xiàng)目,例如列表中的元素、字符串中的字符或其他可迭代對象中的元素。for 循環(huán)針對序列中的每個項(xiàng)目重復(fù)執(zhí)行一段代碼塊,從第一個項(xiàng)目迭代到最后一個項(xiàng)目。
然而,在大多數(shù)情況下,for 循環(huán)可以被更高效的函數(shù) map() 替代。map() 函數(shù)是一種內(nèi)置的高階函數(shù),允許您將給定的函數(shù)應(yīng)用于可迭代對象(如列表、元組或字符串)中的每個項(xiàng)目,并生成一個包含將該函數(shù)應(yīng)用于每個項(xiàng)目的結(jié)果的新可迭代對象。使用 map() 的主要優(yōu)勢是它提供了一種簡潔高效的方式來轉(zhuǎn)換數(shù)據(jù),而無需顯式循環(huán)。
比較 for 循環(huán)和 map() 的函數(shù)的執(zhí)行時間:
def do(): obj = ["hello", "my", "name", "is", "Delight", "!"] new = [] for i in obj: new.append(i.upper())
獲取該函數(shù)的執(zhí)行時間:
>>> import timeit >>> t = timeit.Timer(setup='from __main__ import do', stmt='do()') >>> t.timeit() 1.042804399970919
下面,使用內(nèi)置的 map() 函數(shù)實(shí)現(xiàn)相同的功能,并獲取執(zhí)行時間:
>>> def square(x): ... return x.upper() >>> def do(): ... obj = ["hello", "my", "name", "is", "Delight", "!"] ... map(square, obj) >>> import timeit >>> t = timeit.Timer(setup='from __main__ import do', stmt='do()') >>> t.timeit() 0.37273399997502565
在上面的代碼中,使用 map() 而不是 for 循環(huán)使函數(shù)的運(yùn)行速度提高了約 3 倍。
Python 的 map() 內(nèi)置函數(shù)使我們的代碼更快,主要是因?yàn)樗鼈兪怯?C 語言編寫和編譯的。
四、選擇正確的數(shù)據(jù)結(jié)構(gòu)
選擇正確的數(shù)據(jù)結(jié)構(gòu)對于提高 Python 代碼的速度和效率具有重要影響。不同的數(shù)據(jù)結(jié)構(gòu)針對特定類型的操作進(jìn)行了優(yōu)化,選擇適當(dāng)?shù)臄?shù)據(jù)結(jié)構(gòu)可以實(shí)現(xiàn)更快的查找、插入、刪除和整體性能改進(jìn)。
例如,使用集合進(jìn)行成員測試比使用列表要快得多:
>>> def do():
... fruits_list = ['apple', 'banana', 'orange', 'grape', 'pear']
... 'banana' in fruits_list
... 'kiwi' in fruits_list
>>> import timeit
>>> t = timeit.Timer(setup='from __main__ import do', stmt='do()')
>>> t.timeit()
0.48580530006438494
>>> def do():
... fruits_list = {'apple', 'banana', 'orange', 'grape', 'pear'}
... 'banana' in fruits_set
... 'kiwi' in fruits_set
>>> import timeit
>>> t = timeit.Timer(setup='from __main__ import do', stmt='do()')
>>> t.timeit()
0.34570479998365045
五、減少使用全局變量
全局變量讓你能夠輕松的在程序中共享數(shù)據(jù)。然而,我們謹(jǐn)慎使用使用,只在必要時使用。訪問全局變量比訪問局部變量更慢,要始終盡量減少使用全局變量的情況,特別是在循環(huán)內(nèi)部。
六、向量化
- Python 中的向量化是指對整個數(shù)組或數(shù)據(jù)序列應(yīng)用操作的實(shí)踐,而不是使用顯式循環(huán)迭代單個元素。它利用諸如 NumPy 之類的專門庫,在數(shù)組上高效執(zhí)行逐元素操作,利用硬件級別的優(yōu)化,減少對顯式循環(huán)結(jié)構(gòu)的需求。
- 如果進(jìn)行數(shù)值計(jì)算,請考慮使用像 NumPy 這樣的庫,它提供了經(jīng)過優(yōu)化的數(shù)組操作,比在標(biāo)準(zhǔn) Python 列表中逐元素操作要快得多。
- 向量化是科學(xué)計(jì)算和數(shù)值分析的基本概念,在使 Python 成為強(qiáng)大的數(shù)據(jù)分析、機(jī)器學(xué)習(xí)和其他涉及大型數(shù)據(jù)集的計(jì)算任務(wù)的語言中起著關(guān)鍵作用。
七、避免不必要的函數(shù)調(diào)用
避免在 Python 中進(jìn)行不必要的函數(shù)調(diào)用,對于提高代碼的效率和性能非常重要。
函數(shù)調(diào)用可能會引入開銷,消耗內(nèi)存,并降低程序的執(zhí)行速度。盡量合并不必要的調(diào)用操作。
八、避免不必要的導(dǎo)入語句
import statements can be executed just about anywhere. It’s often useful to place them inside functions to restrict their visibility and/or reduce initial startup time. – Python.org
在 Python 中避免不必要的導(dǎo)入語句對于保持干凈、高效和可讀的代碼至關(guān)重要。不必要的導(dǎo)入有時可能導(dǎo)致模塊之間的循環(huán)依賴。這可能會在運(yùn)行時引發(fā)問題,并使重構(gòu)代碼變得更加困難。
盡管現(xiàn)代文本編輯器現(xiàn)在可以很容易地幫助您找到程序中未使用的代碼,但添加未使用的導(dǎo)入可能會使這些編輯器混淆,增加誤判的風(fēng)險。
九、編譯您的代碼
如果性能是你的程序執(zhí)行的關(guān)鍵因素,請考慮使用像 Cython 這樣的工具將您的代碼編譯為 C 或 C++。這可以顯著提高程序的性能。
通過使用 Cython 等工具,您可以充分利用 Python 的易用性和 C 或 C++ 等編譯語言的高性能特性。
十、分析你的代碼
The first step to speeding up your program is learning where the bottlenecks lie. – Python.org
在 Python 中進(jìn)行性能分析就是是測量和分析代碼的執(zhí)行時間和資源使用情況,以查找代碼中的瓶頸和優(yōu)化機(jī)會。
Python 提供了各種內(nèi)置的性能分析工具,如 profile 和 timeit(我們已經(jīng)使用過)。
以下是使用 profile 模塊對一個名為 do() 的函數(shù)進(jìn)行性能分析的示例:
import profile
profile.run('do()')
十一、及時了解Python的更新發(fā)布
較新的 Python 版本通常包括性能增強(qiáng)、錯誤修復(fù)、安全更新等。
Python 不斷發(fā)展,新版本通常包含性能改進(jìn)。保持更新的解釋器可以幫助您從這些改進(jìn)中受益。
然而,重要的是在保持最新狀態(tài)和考慮升級對現(xiàn)有項(xiàng)目的影響之間取得平衡。如果您有一個龐大的代碼庫或依賴于尚不與最新版本兼容的第三方庫,可能需要謹(jǐn)慎升級。
在本文中,我們介紹了各種技術(shù)、策略和最佳實(shí)踐,使開發(fā)人員能在克服 Python 某些性能限制的同時,充分發(fā)揮其潛力。
需要注意的是,優(yōu)化不僅僅是從代碼的執(zhí)行時間中減少毫秒或微秒,而是編寫可讀性強(qiáng)、可擴(kuò)展性好和可維護(hù)性高的代碼。
到此這篇關(guān)于Python代碼優(yōu)化指南:讓你代碼5X倍速的文章就介紹到這了,更多相關(guān)Python代碼優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python彩色化Linux的命令行終端界面的代碼實(shí)例分享
美化Linux的terminal終端顯示的方法多種多樣,這里我們給出一個利用Python彩色化Linux的命令行終端界面的代碼實(shí)例分享,包括一個Linux下簡便執(zhí)行Python程序的方法,需要的朋友可以參考下2016-07-07
Python中使用json.load()和json.loads()加載json數(shù)據(jù)的方法實(shí)例
在python編程中,我們經(jīng)常要用到j(luò)son對象作為數(shù)據(jù)交換格式,下面這篇文章主要給大家介紹了關(guān)于Python中使用json.load()和json.loads()加載json數(shù)據(jù)的方法實(shí)例,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
Python裝飾器限制函數(shù)運(yùn)行時間超時則退出執(zhí)行
今天小編就為大家分享一篇關(guān)于Python裝飾器限制函數(shù)運(yùn)行時間超時則退出執(zhí)行,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-04-04
Python實(shí)現(xiàn)npy/mat文件的保存與讀取
除了常用的csv文件和excel文件之外,我們還可以通過Python把數(shù)據(jù)保存文npy文件格式和mat文件格式。本文為大家展示了實(shí)現(xiàn)npy文件與mat文件的保存與讀取的示例代碼,需要的可以參考一下2022-04-04
Pyinstaller+Pipenv打包Python文件的實(shí)現(xiàn)示例
相信大家都試過將Python文件進(jìn)行打包,本文主要介紹了Pyinstaller+Pipenv打包Python文件,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
使用Python創(chuàng)建簡單的HTTP服務(wù)器的方法步驟
這篇文章主要介紹了使用Python創(chuàng)建簡單的HTTP服務(wù)器的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
基于PyQt實(shí)現(xiàn)多頁面切換的詳細(xì)教程
在實(shí)際桌面應(yīng)用開發(fā)中,頁面切換不僅僅是簡單的按鈕切換,往往還涉及到頁面間的數(shù)據(jù)傳遞、動態(tài)內(nèi)容更新、以及更復(fù)雜的UI布局,本文將基于PyQt的QStackedWidget,詳細(xì)講解如何實(shí)現(xiàn)多頁面切換,需要的朋友可以參考下2025-12-12

