不要再寫(xiě)低效的Python代碼,一些小Tips
hello,本期將和大家一起繼續(xù)拓展一些優(yōu)化 Python 代碼性能的有用技巧,一起看看吧
1. 使用 Python 調(diào)試器 (pdb)
Python 調(diào)試器允許單步執(zhí)行代碼,可以使用它來(lái)查找瓶頸并優(yōu)化代碼
import pdb
def calculate_sum(n):
? ?total = 0
? ?for i in range(n):
? ? ? ?pdb.set_trace()
? ? ? ?total += i
? ?return total
calculate_sum(5)
該例展示了如何使用 Python 調(diào)試器 (pdb) 來(lái)優(yōu)化函數(shù)。pdb.set_trace() 語(yǔ)句放置在循環(huán)內(nèi)以在每次迭代時(shí)進(jìn)入調(diào)試器。這使得能夠在每次迭代時(shí)檢查變量和代碼流,真得很常用~
2. 使用內(nèi)置函數(shù)與庫(kù)
Python 提供了各種可以高效執(zhí)行復(fù)雜任務(wù)的內(nèi)置函數(shù)和庫(kù)。例如,使用?map()?將函數(shù)應(yīng)用于列表中的每個(gè)元素,或使用 pandas 庫(kù)來(lái)操作 DataFrame 中的數(shù)據(jù)
# Example of using map() function to apply a function to a list
lst = [1, 2, 3, 4, 5]
new_lst = list(map(lambda x: x * 2, lst)) ?
# Multiply each element in the list by 2
print(new_lst)
# Output: [2, 4, 6, 8, 10]
3. 使用生成器
生成器是一種在 Python 中創(chuàng)建迭代器的高效節(jié)省內(nèi)存方式。通常用于迭代大型數(shù)據(jù)集而無(wú)需將它們存儲(chǔ)在內(nèi)存中
# Example of using a generator to iterate over a large dataset
def read_file(filename):
?with open(filename) as file:
? ?for line in file:
? ? ?yieldline.strip()
? ? ? ?for line in read_file("data.txt"):
? ? ? ? ?print(line)
該例定義了一個(gè)函數(shù) read_file,它逐行讀取文件并使用生成器在讀取時(shí)生成每一行。該函數(shù)使用 with 語(yǔ)句打開(kāi)文件,以確保文件在完成后正確關(guān)閉。當(dāng)以文件名作為參數(shù)調(diào)用該函數(shù)時(shí),它返回一個(gè)生成器對(duì)象。然后 for 循環(huán)遍歷生成器返回的每一行并將其打印到控制臺(tái)。
4. 使用元組與字典推導(dǎo)
與列表推導(dǎo)類(lèi)似
# Example of using set comprehension to create a new set
lst = [1, 2, 3, 4, 5]
new_set = {x * 2 for x in lst} ?
# Multiply each element in the list by 2 and create a new set
print(new_set) ?
# Output: {2, 4, 6, 8, 10}
# Example of using dictionary comprehension to create a new dictionary
lst = [("apple", 2), ("banana", 3), ("orange", 4)]
new_dict = {k: v for k, v in lst} ?
# Convert the list of tuples to a dictionary
print(new_dict) ?
# {'apple': 2, 'banana': 3, 'orange': 4}
5. 使用最有效的數(shù)據(jù)結(jié)構(gòu)
高效的數(shù)據(jù)結(jié)構(gòu)可以通過(guò)為各種操作提供不同的時(shí)間復(fù)雜度來(lái)極大地提高 Python 代碼的性能。選擇最佳數(shù)據(jù)結(jié)構(gòu)會(huì)對(duì)代碼速度產(chǎn)生重大影響
例如,對(duì)于較大的列表,使用列表實(shí)現(xiàn)隊(duì)列數(shù)據(jù)結(jié)構(gòu)可能會(huì)很慢,因?yàn)閺牧斜淼拈_(kāi)頭追加和彈出很慢。相反,使用專(zhuān)為實(shí)現(xiàn)隊(duì)列而設(shè)計(jì)的 collections.deque 對(duì)象可以顯著提高性能
下例說(shuō)明正確的數(shù)據(jù)結(jié)構(gòu)如何在搜索數(shù)字列表的最大值和最小值時(shí)提高代碼性能:
# Using a list to find max and min values
numbers = [5, 10, 2, 8, 1]
max_val = max(numbers)
min_val = min(numbers)
# Using a heap to find max and min values
import heapq
numbers = [5, 10, 2, 8, 1]
max_val = heapq.nlargest(1, numbers)[0]
min_val = heapq.nsmallest(1, numbers)[0]
6. 使用裝飾器簡(jiǎn)化代碼
關(guān)于裝飾器之前有專(zhuān)門(mén)發(fā)過(guò)一篇
裝飾器是 Python 中的一個(gè)強(qiáng)大工具,可以修改函數(shù)或類(lèi)的行為??捎糜诤?jiǎn)化代碼并提高其性能
例如,假設(shè)有一個(gè)可能引發(fā)異常的函數(shù):
def potentially_error_prone_function():
? ?if some_condition:
? ? ? ?raise ValueError("Oops!")
? ?return "Success"
可以將此函數(shù)包裝在 try/except 塊中以處理異常:
def error_handling_wrapper(func):
? ?def wrapper():
? ? ? ?try:
? ? ? ? ? ?result = func()
? ? ? ?except Exception as e:
? ? ? ? ? ?print("An error occurred:", e)
? ? ? ? ? ?return None
? ? ? ?return result
? ?return wrapper
@error_handling_wrapper
def potentially_error_prone_function():
? ?if some_condition:
? ? ? ?raise ValueError("Oops!")
? ?return "Success"
如上,當(dāng)調(diào)用 potentially_error_prone_function() 時(shí),如果引發(fā)異常,它將被捕獲并打印一條消息,而不是程序崩潰,當(dāng)然,項(xiàng)目要落地還是要深挖為何引發(fā)異常,這個(gè)虧我算是吃太多了
7. 盡可能避免使用 try-except
和上面不沖突,try-except 塊會(huì)降低代碼速度,可以改用條件語(yǔ)句來(lái)處理錯(cuò)誤
# Bad Code
def divide(a, b):
? ?try:
? ? ? ?result = a / b
? ?except ZeroDivisionError:
? ? ? ?result = None
? ?return result
# Good Code
def divide(a, b):
? ?if b == 0:
? ? ? ?return None
? ?else:
? ? ? ?return a / b
該例使用 try-except 塊來(lái)處理分母為零的情況。此方法可能很慢且效率低下,尤其是當(dāng) try-except 塊位于經(jīng)常調(diào)用的函數(shù)中時(shí)。另一方面,好的代碼應(yīng)該在執(zhí)行除法前檢查分母是否為零,這是處理零分母情況的一種更快、更有效的方法。
8. 使用Cython加速代碼
Cython 是 Python 的超集,允許為 Python 編寫(xiě) C 擴(kuò)展,可以顯著加快我們的代碼速度,特別是對(duì)于計(jì)算密集型任務(wù)。
下例是使用 Cython 加速計(jì)算平方和的 Python 函數(shù)的示例:
# Python Code
def calculate_sum(n):
? ?total = 0
? ?for i in range(n):
? ? ? ?total += i
? ?return total
# Cython Code
%%cython
def calculate_sum_cython(int n):
? ?cdef int total = 0
? ?for i in range(n):
? ? ? ?total += i
? ?return total
首先創(chuàng)建一個(gè)包含該函數(shù)的 Cython 版本的 .pyx 文件
# file: sum_squares_cython.pyx
def sum_squares_cython(int n):
? ?cdef int total = 0
? ?cdef int i
? ?for i in range(n):
? ? ? ?total += i**2
? ?return total
我們?yōu)樽兞刻砑恿祟?lèi)型聲明 (cdef int),這允許 Cython 生成更快的 C 代碼
要將 Cython 代碼編譯成 Python 擴(kuò)展模塊,需要?jiǎng)?chuàng)建一個(gè) setup.py 文件:
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("sum_squares_cython.pyx"))
現(xiàn)在可以通過(guò)運(yùn)行 python setup.py build_ext --inplace 來(lái)編譯擴(kuò)展模塊
這將創(chuàng)建一個(gè)名為 sum_squares_cython.so(或 Windows 上的 sum_squares_cython.pyd)的文件
最后,可以在 Python 中導(dǎo)入并使用 sum_squares_cython 函數(shù):
from sum_squares_cython import sum_squares_cython
result = sum_squares_cython(1000000)
print(result)
以上就是本期全部?jī)?nèi)容,下次再見(jiàn)~