在日常的開發中,我們經常需要編寫高效的代碼來提高程序的性能和響應速度。Python作為一門高級語言,在語法簡潔、可讀性強的同時也具備快速實現功能的能力。然而,如果不使用一些小技巧和優化方法,Python也可能運行緩慢,這將影響用戶體驗和系統的整體性能。本文將從多個方面介紹一些提高Python代碼效率的小技巧,並結合實例來演示如何將Python的sleep clock更智能化。
一、避免重複計算
在Python編程中,如果有些代碼需要重複執行,而且每次計算的結果是相同的,那麼這個計算就顯得非常浪費時間。解決這個問題的方法就是緩存。使用Python中的緩存模塊`functools.lru_cache()`可以很方便地開啟緩存機制。
下面是一個實例,使用`lru_cache()`計算斐波那契數列的第n項。
import functools
@functools.lru_cache()
def fibonacci(n):
if n in (0, 1):
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
在上面的代碼中,裝飾器`@functools.lru_cache()`用於啟用緩存機制,防止重複計算。
二、使用生成器
對於一些需要大量計算的操作,可以使用生成器進行優化。生成器是Python中比較常用的迭代器,可以幫助我們省去不少開銷。
下面是一個使用生成器的例子,將兩個列表的元素逐個相加。
def add_lists(list1, list2):
for i, j in zip(list1, list2):
yield i+j
a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
for c in add_lists(a, b):
print(c)
在上面的代碼中,`add_lists()`函數返回一個生成器,每次返回兩個列表中對應位置元素的和。
三、使用set代替list
在Python中,set是一種內置的無序可迭代集合,具有快速查找和去重的優點。如果我們需要統計列表中不同元素的數量,將list轉換為set可以大幅提升效率,避免重複計算。
下面是一個統計列表中元素數量的實例,分別使用list和set實現。
import random
import time
# 使用list統計元素數量
mylist = [random.randint(0, 1000000) for _ in range(1000000)]
start = time.time()
freq = {}
for i in mylist:
if i in freq:
freq[i] += 1
else:
freq[i] = 1
print("Using list: ", time.time() - start)
# 使用set統計元素數量
myset = set(mylist)
start = time.time()
freq = {}
for i in myset:
freq[i] = mylist.count(i)
print("Using set: ", time.time() - start)
在上面的代碼中,使用list和set分別統計1000000個元素的數量,結果就可以看出,使用set的效率比使用list更高。
四、使用並行編程
對於複雜耗時的操作,Python也提供了一些並行編程的庫,如multiprocessing和concurrent.futures。使用這些庫可以開啟多個線程或進程來同時處理任務,加速程序的運行。
下面是一個簡單的使用multiprocessing進行並行計算的實例,計算1~1000000之間所有整數的平方和。
from multiprocessing import Pool
def calc_square(num):
return num*num
if __name__ == '__main__':
with Pool(4) as p:
result = p.map(calc_square, range(1, 1000001))
print(sum(result))
在上面的代碼中,使用`Pool(4)`開啟了4個進程,使用`map()`方法將1~1000000之間所有整數傳遞給函數`calc_square()`,用`sum()`方法計算平方和。使用多進程執行可以大幅縮短代碼運行的時間。
五、避免使用循環
使用循環的操作本身是非常消耗時間和性能的,因此我們應該儘可能地避免使用循環。Python內置的一些函數可以幫助我們實現常見的操作,避免重新編寫循環。
下面是一個使用Python內置函數進行替換的實例,將列表中的非0元素移動到列表前面。
mylist = [1, 0, 2, 0, 3, 0, 4, 0]
# 使用循環
newlist = []
for i in mylist:
if i != 0:
newlist.append(i)
for i in range(mylist.count(0)):
newlist.append(0)
print(newlist)
# 使用內置函數
newlist = list(filter(lambda x: x != 0, mylist))
newlist.extend([0]*mylist.count(0))
print(newlist)
在上面的代碼中,使用循環和內置函數分別實現了將0元素移到列表後面的功能,比較兩種方法可以看到,使用內置函數實現代碼更簡潔、效率更高。
六、使用進程池進行頻繁的IO操作
Python的IO操作非常消耗時間和性能,特別是在文件操作和網絡通信中。對於這種頻繁的IO操作,可以使用進程池進行優化。可以通過創建多個進程來並行處理IO操作,從而加速程序的運行。
下面是一個使用進程池進行文件複製的實例,將一個文件夾下的所有文件複製到另一個文件夾中。
import os
from multiprocessing import Pool
def copy_file(src, dst):
with open(src, 'rb') as f_src:
with open(dst, 'wb') as f_dst:
while True:
block = f_src.read(1024*1024)
if not block:
break
f_dst.write(block)
def copy_files(src_dir, dst_dir):
if not os.path.exists(dst_dir):
os.mkdir(dst_dir)
with Pool(4) as p:
for file_name in os.listdir(src_dir):
src = os.path.join(src_dir, file_name)
dst = os.path.join(dst_dir, file_name)
if os.path.isfile(src):
p.apply_async(copy_file, args=(src, dst))
p.close()
p.join()
if __name__ == '__main__':
copy_files('./source', './destination')
在上面的代碼中,使用`Pool(4)`開啟了4個進程來並行處理文件複製。使用進程池進行IO操作可以大幅提升代碼的運行效率。
七、使用裝飾器統計函數執行時間
在開發過程中,需要經常統計函數的執行時間,以便定位代碼瓶頸。使用裝飾器可以很方便地實現函數執行時間的統計。
下面是一個統計函數執行時間的裝飾器示例。
import functools
import time
def timethis(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(func.__name__, end - start)
return result
return wrapper
@timethis
def countdown(n):
while n > 0:
n -= 1
if __name__ == '__main__':
countdown(10000000)
在上面的代碼中,定義了一個裝飾器`@timethis`,用於統計函數的執行時間。在`countdown()`函數上添加裝飾器即可輸出函數執行時間。
八、避免重複導入模塊
在Python中,導入模塊的過程會檢查sys.path中的目錄,如果找到指定模塊,則將該模塊加載至內存中。這個過程有時非常耗時,特別是在模塊龐大的情況下。因此,在開發中,應該避免重複導入模塊。
下面是一個避免重複導入模塊的例子。
import timeit
def test_import():
import math
def test_from_import():
from math import sqrt
t_import = timeit.Timer(stmt=test_import)
print('Import time:', t_import.timeit(100000))
t_from_import = timeit.Timer(stmt=test_from_import)
print('From import time:', t_from_import.timeit(100000))
在上面的代碼中,分別使用普通導入和from導入方式進行模塊導入,並使用timeit模塊比較兩者耗時。可以看到,使用from導入方式比普通導入更快。
九、使用緩存
在開發過程中,有些函數需要進行大量計算,而且每次計算得到的結果都相同,這樣重複計算會浪費時間和性能。使用緩存可以避免重複計算,並提升代碼執行效率。
下面是一個使用緩存函數的例子。
import functools
@functools.lru_cache(maxsize=256)
def fibonacci(n):
if n in (1, 2):
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(50))
在上面的代碼中,使用Python內置的緩存裝飾器`@functools.lru_cache()`將函數結果緩存起來,避免重複計算。
總結
在Python開發中,優化代碼是實現高效程序的關鍵。以上是一些簡單易用的技巧和方法,可以幫助我們提升Python程序的性能和響應速度。
1、使用`functools.lru_cache()`開啟緩存機制,避免重複計算。
2、使用生成器進行計算,減少計算開銷。
3、使用set代替list進行去重和計數。
4、使用並行編程加速程序運行。
5、避免使用循環,儘可能使用Python內置函數來代替循環。
6、使用進程池進行頻繁的IO操作,提升程序效率。
7、使用裝飾器統計函數執行時間。
8、避免重複導入模塊,使用from-import方式進行模塊導入。
9、使用緩存避免重複計算,提升程序性能。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/227795.html