python作為使用最廣泛的編程語言之一,有著無窮無盡的第三方非標(biāo)準(zhǔn)庫(kù)的支持。
簡(jiǎn)單的語法、優(yōu)雅的代碼塊使其在各個(gè)業(yè)務(wù)領(lǐng)域都混的風(fēng)生水起,除了這些優(yōu)點(diǎn),python有一個(gè)經(jīng)常被人詬病的缺點(diǎn)那就是運(yùn)行速度。
小伙伴通過下面的五個(gè)python開發(fā)技巧,來充分提高python代碼塊的運(yùn)行速度,并且提供了各個(gè)python技巧的使用后的運(yùn)行時(shí)間的統(tǒng)計(jì)來佐證。
開始之前小伙伴先可以開發(fā)一個(gè)統(tǒng)計(jì)函數(shù)運(yùn)行時(shí)間的python裝飾器用于后面我們對(duì)各個(gè)python技巧使用后的時(shí)間統(tǒng)計(jì)。
# 導(dǎo)入時(shí)間提取的time模塊
from time import time
import dis
def compute_time(func_):
'''
計(jì)算函數(shù)的運(yùn)行時(shí)間
'''
def func_time(*arg, **kw):
t1 = time()
result = func_(*arg, **kw)
t2 = time()
print(f"{func_.__name__: >10} : {t2 - t1:.6f} 秒")
return result
return func_time
上述的compute_time時(shí)間計(jì)算函數(shù)我們開發(fā)好了,可以開發(fā)一個(gè)hello_world函數(shù)測(cè)試一下使用是否正常。
@compute_time
def hello_world():
print("hello_world!")
hello_world()
# hello_world!
# hello_world : 0.000000 秒
通過hello_world函數(shù)的測(cè)試,證明我們的時(shí)間裝飾器compute_time能夠正常統(tǒng)計(jì)出函數(shù)所運(yùn)行的時(shí)間。
接下來,我們開始正式的介紹下面的五種方式來提高python的運(yùn)行速度并提供時(shí)間運(yùn)行的結(jié)果。
1、合理使用標(biāo)準(zhǔn)或非標(biāo)準(zhǔn)庫(kù)
在開發(fā)過程中絕對(duì)不能小看python的標(biāo)準(zhǔn)或非標(biāo)準(zhǔn)庫(kù),說實(shí)話我們自己有時(shí)候?qū)懙耐瑯拥臉I(yè)務(wù)代碼塊確實(shí)是沒有大佬們完美。
比如下面這個(gè)業(yè)務(wù)我們需要將一個(gè)python列表中的值轉(zhuǎn)換成字符串,首先看看下面的代碼塊的寫法。
# 初始化一個(gè)list列表
list_ = ['a', 'b', 'c'] * 10000
@compute_time
def func_1(list_=None):
'''
列表元素轉(zhuǎn)字符串函數(shù)
'''
str_ = ''
for s in list_:
str_ = str_ + s
return str_
func_1(list_)
# func_1 : 0.001999 秒
通過上面的func_1函數(shù)的執(zhí)行情況使用自己寫的傳統(tǒng)的方式來轉(zhuǎn)換步驟比較繁雜,并且花費(fèi)了0.001999 秒的時(shí)間。
@compute_time
def func_2(list_=None):
'''
列表元素轉(zhuǎn)字符串
'''
return ''.join(list_)
func_2(list_)
# func_2 : 0.000000 秒
相比func_1函數(shù)的運(yùn)行時(shí)間,func_2運(yùn)行的時(shí)間幾乎可以忽略不計(jì),六位數(shù)的小數(shù)根本看不出來變化。
2、減少循環(huán)的使用
從平常開發(fā)的過程中其實(shí)已經(jīng)發(fā)現(xiàn),使用列表推導(dǎo)式、迭代式等的可序列化數(shù)據(jù)處理方式要比for循環(huán)更加的便捷、高效。
下面我們同樣可以通過一個(gè)例子來說明問題,比如我們需要挑選出一個(gè)list列表中可以被2整除的數(shù)。
# 初始化循環(huán)次數(shù)n
n = 100000
@compute_time
def func_3(n=None):
list_ = []
for m in range(n):
if m % 2 == 0:
list_.append(m)
return list_
@compute_time
def func_4(n=None):
return [m for m in range(n) if m % 2 == 0]
func_3(n)
func_4(n)
# func_3 : 0.004986 秒
# func_4 : 0.003014 秒
通過func_3函數(shù)、func_4函數(shù)的比較,首先func_4的方式比func_3精簡(jiǎn)了許多。
并且時(shí)間上func_4使用列表推導(dǎo)式的方式比普通的for循環(huán)運(yùn)行速度上快了1/4的時(shí)間。
3、注意重復(fù)代碼運(yùn)行
關(guān)于代碼的重復(fù)運(yùn)行這個(gè)在我們通常的開發(fā)方式中都能體會(huì)到,也就是本可以作為公共代碼塊運(yùn)行一次就可以。
可以卻將能夠公共使用的代碼塊加入到了循環(huán)當(dāng)中,這樣只會(huì)影響代碼塊的執(zhí)行效率。
比如我們需要使用python的re模塊去搜索字符串中的某一些元素,下面通過兩種方式來比較時(shí)間結(jié)果。
# 導(dǎo)入正則表達(dá)式匹配模塊
import re
@compute_time
def func_5(str_=None):
for s in str_:
result = re.search(r'a*[a-z]?c', s)
@compute_time
def func_6(str_=None):
repx = re.compile(r'a*[a-z]?c')
for s in str_:
result = repx.search(s)
func_5('abcdefg1234oks' * 1000)
func_6('abcdefg1234oks' * 1000)
# func_5 : 0.006999 秒
# func_6 : 0.002000 秒
對(duì)比func_5和func_6的業(yè)務(wù)實(shí)現(xiàn)方式,我們將re模塊的compile正則匹配對(duì)象直接放到for循環(huán)的外層,運(yùn)行時(shí)間直接就減少了3倍不止。
是因?yàn)樵谘h(huán)中直接使用search匹配正則對(duì)象,會(huì)在循環(huán)中不斷地創(chuàng)建正則匹配對(duì)象,這樣就
增加了for循環(huán)的處理負(fù)擔(dān),導(dǎo)致速度變慢。
4、減少全局變量使用
在說明這一點(diǎn)的時(shí)候,我們要明白全局變量在程序運(yùn)行的過程中是一直存在的不會(huì)消失。
全局變量太多就會(huì)導(dǎo)致運(yùn)行期間占用的內(nèi)存太大,相比全局變量使用局部變量就會(huì)變得更加的高效。
下面我們通過兩種方式的使用實(shí)例,來對(duì)比全局變量和局部變量的運(yùn)行時(shí)間。
mes_1 = 'ss1'
mes_2 = 'ss2'
mes_3 = 'ss3'
@compute_time
def func_7():
result = mes_1 + mes_2 + mes_3
return result
@compute_time
def func_8():
me_1 = 'ss1'
me_2 = 'ss2'
me_3 = 'ss3'
result = me_1 + me_2 + me_3
return result
func_7()
func_8()
# func_7 : 0.000997 秒
# func_8 : 0.000000 秒
上面我們做了一個(gè)普通的加法計(jì)算已經(jīng)說明了問題,func_8函數(shù)使用局部變量的方式確實(shí)速度更快。
5、使用合理的數(shù)據(jù)結(jié)構(gòu)
在大多數(shù)的python開發(fā)過程中,想必很多人都是為了方便更多的時(shí)候使用的是list列表的方式來處理數(shù)據(jù)。
Python 有四種內(nèi)置的數(shù)據(jù)結(jié)構(gòu):列表、元組、集合、字典,在合適的業(yè)務(wù)場(chǎng)景中使用合適的數(shù)據(jù)結(jié)構(gòu)來處理數(shù)據(jù)同樣能提高計(jì)算的執(zhí)行效率。
比如:下面我們將從一個(gè)list列表和tuple元組來提取對(duì)應(yīng)索引位置上面的值。
@compute_time
def func_9():
data = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
print(data[3])
@compute_time
def func_10():
data = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')
print(data[3])
func_9()
func_10()
# func_9 : 0.000000 秒
# func_10 : 0.000000 秒
通過執(zhí)行func_9和func_10函數(shù),我們發(fā)現(xiàn)時(shí)間上兩者的差距不大,起碼在六位小數(shù)之內(nèi)是分辨不出結(jié)果的。
print('func_9匯編產(chǎn)生的機(jī)器碼:')
dis.dis(func_9)
print('func_10匯編產(chǎn)生的機(jī)器碼:')
dis.dis(func_10)
最后,我們分別查看了func_9和func_10的匯編機(jī)器碼,發(fā)現(xiàn)明顯list列表處理產(chǎn)生的機(jī)器碼更多。
# func_9匯編產(chǎn)生的機(jī)器碼:
# 30 0 LOAD_GLOBAL 0 (time)
# 2 CALL_FUNCTION 0
# 4 STORE_FAST 2 (t1)
#
# 31 6 LOAD_DEREF 0 (func_)
# 8 LOAD_FAST 0 (arg)
# 10 LOAD_FAST 1 (kw)
# 12 CALL_FUNCTION_EX 1
# 14 STORE_FAST 3 (result)
#
# 32 16 LOAD_GLOBAL 0 (time)
# 18 CALL_FUNCTION 0
# 20 STORE_FAST 4 (t2)
#
# 33 22 LOAD_GLOBAL 1 (print)
# 24 LOAD_DEREF 0 (func_)
# 26 LOAD_ATTR 2 (__name__)
# 28 LOAD_CONST 1 (' >10')
# 30 FORMAT_VALUE 4 (with format)
# 32 LOAD_CONST 2 (' : ')
# 34 LOAD_FAST 4 (t2)
# 36 LOAD_FAST 2 (t1)
# 38 BINARY_SUBTRACT
# 40 LOAD_CONST 3 ('.6f')
# 42 FORMAT_VALUE 4 (with format)
# 44 LOAD_CONST 4 (' 秒')
# 46 BUILD_STRING 4
# 48 CALL_FUNCTION 1
# 50 POP_TOP
#
# 34 52 LOAD_FAST 3 (result)
# 54 RETURN_VALUE
# func_10匯編產(chǎn)生的機(jī)器碼:
# 30 0 LOAD_GLOBAL 0 (time)
# 2 CALL_FUNCTION 0
# 4 STORE_FAST 2 (t1)
#
# 31 6 LOAD_DEREF 0 (func_)
# 8 LOAD_FAST 0 (arg)
# 10 LOAD_FAST 1 (kw)
# 12 CALL_FUNCTION_EX 1
# 14 STORE_FAST 3 (result)
往期精彩
這款基于ChatGPT4的開發(fā)工具,程序猿要小心了!
剛剛在GitHub發(fā)現(xiàn)的開數(shù)據(jù)源可視化分析工具,只通過配置的方式即可完成個(gè)性化的可視化應(yīng)用制作!文章來源:http://www.zghlxwxcb.cn/news/detail-413276.html
自動(dòng)化辦公:python文件分類器,一鍵完成雜亂無章的文件整理,已打包成exe可自行下載!文章來源地址http://www.zghlxwxcb.cn/news/detail-413276.html
到了這里,關(guān)于從這五個(gè)方面提升python的執(zhí)行效率,才是軟件開發(fā)層面需要考慮的問題!的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!