提升Python的執行效率的技巧有哪些

王林
發布: 2023-05-11 14:13:06
轉載
1393 人瀏覽過

開始之前小夥伴先可以開發一個統計函數運行時間的python裝飾器用於後面我們對各個python技巧使用後的時間統計。

# 导入时间提取的time模块
from time import time

import dis


def compute_time(func_):
    '''
    计算函数的运行时间
    '''

    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時間計算函數我們開發好了,可以開發一個hello_world函數來測試一下使用是否正常。

@compute_time
def hello_world():
    print("hello_world!")


hello_world()

# hello_world!
# hello_world : 0.000000 秒
登入後複製

透過hello_world函數的測試,證明我們的時間裝飾器compute_time能夠正常統計出函數所執行的時間。

接下來,我們開始正式的介紹下面的五種方式來提高python的運行速度並提供時間運行的結果。

1、合理使用標準或非標準函式庫

在開發過程中絕對不能小看python的標準或非標準函式庫,說實話我們自己有時候寫的同樣的商業程式碼區塊確實是沒有大佬們完美。

例如下面這個業務我們需要將一個python列表中的值轉換成字串,首先看看下面的程式碼區塊的寫法。

# 初始化一个list列表
list_ = ['a', 'b', 'c'] * 10000


@compute_time
def func_1(list_=None):
    '''
    列表元素转字符串函数
    '''
    str_ = ''
    for s in list_:
        str_ = str_ + s
    return str_


func_1(list_)


# func_1 : 0.001999 秒
登入後複製

透過上面的func_1函數的執行情況使用自己寫的傳統的方式來轉換步驟比較繁雜,並且花費了0.001999 秒的時間。

@compute_time
def func_2(list_=None):
    '''
    列表元素转字符串
    '''
    return ''.join(list_)


func_2(list_)

# func_2 : 0.000000 秒
登入後複製

比起func_1函數的運行時間,func_2運行的時間幾乎可以忽略不計,六位數的小數根本看不出來變化。

2、減少迴圈的使用

從平常開發的過程中其實已經發現,使用列表推導式、迭代式等的可序列化資料處理方式要比for迴圈更加的便捷、高效。

下面我們同樣可以透過一個例子來說明問題,例如我們需要挑選出一個list列表中可以被2整除的數。

# 初始化循环次数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函數、func_4函數的比較,首先func_4的方式比func_3精簡了許多。

並且時間上func_4使用列表推導式的方式比普通的for循環運行速度上快了1/4的時間。

3、注意重複程式碼運行

關於程式碼的重複運行這個在我們通常的開發方式中都能體會到,也就是本來可以作為公共程式碼區塊運行一次就可以。

可以卻將能夠公共使用的程式碼區塊加入了循環當中,這樣只會影響程式碼區塊的執行效率。

例如我們需要使用python的re模組去搜尋字串中的某一些元素,下面透過兩種方式來比較時間結果。

# 导入正则表达式匹配模块
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 秒
登入後複製

比較func_5和func_6的業務實作方式,我們將re模組的compile正規匹配物件直接放到for迴圈的外層,運行時間直接就減少了3倍不止。

是因為在循環中直接使用search匹配正則對象,會在循環中不斷地創建正則匹配對象,這樣就
增加了for循環的處理負擔,導致速度變慢。

4、減少全域變數使用

在說明這一點的時候,我們要明白全域變數在程式運行的過程中是一直存在的不會消失。

全域變數太多就會導致運行期間佔用的記憶體太大,相比全域變數使用局部變數就會變得更加的高效。

下面我們透過兩種方式的使用實例,來比較全域變數和局部變數的運行時間。

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 秒
登入後複製

上面我們做了一個普通的加法計算已經說明了問題,func_8函數使用局部變數的方式確實速度更快。

5、使用合理的資料結構

在大多數的python開發過程中,想必很多人都是為了方便更多的時候使用的是list列表的方式來處理資料。

Python 有四種內建的資料結構:清單、元組、集合、字典,在適當的業務場景中使用適當的資料結構來處理資料同樣能提高計算的執行效率。

例如:下面我們將從一個list列表和tuple元組來提取對應索引位置上面的值。

@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 秒
登入後複製

透過執行func_9和func_10函數,我們發現時間上兩者的差距不大,起碼在六位小數之內是分辨不出結果的。

print('func_9汇编产生的机器码:')
dis.dis(func_9)

print('func_10汇编产生的机器码:')
dis.dis(func_10)
登入後複製

最後,我們分別查看了func_9和func_10的彙編機器碼,發現明顯list列表處理產生的機器碼更多。

# func_9汇编产生的机器码:
#  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汇编产生的机器码:
#  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)
登入後複製

以上是提升Python的執行效率的技巧有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:yisu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!