自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

九個技巧,讓你的Python代碼運行得更快!

開發(fā) 前端
?在編程語言的討論中,我們經(jīng)常聽到 “Python 太慢了” 的聲音,這往往掩蓋了 Python 的許多優(yōu)點。但事實上,如果你能以 Pythonic 的方式編寫代碼,Python 可以非常快。

在編程語言的討論中,我們經(jīng)常聽到 “Python 太慢了” 的聲音,這往往掩蓋了 Python 的許多優(yōu)點。但事實上,如果你能以 Pythonic 的方式編寫代碼,Python 可以非??臁?/p>

細節(jié)決定成敗。經(jīng)驗豐富的 Python 開發(fā)者擁有一系列微妙而強大的技巧,這些技巧可以顯著提高代碼的性能。

這些技巧乍一看可能微不足道,但它們可以帶來效率的大幅提升。讓我們深入探討這 9 種方法,改變你編寫和優(yōu)化 Python 代碼的方式。

1. 更快的字符串連接:巧妙選擇 "join()" 或 "+"

如果有很多字符串需要處理,字符串連接就會成為 Python 程序的瓶頸。

在 Python 中,字符串連接基本上有兩種方式:

  • 使用join()函數(shù)將一個字符串列表合并為一個
  • 使用+或+=符號將每個字符串添加到一個字符串中

那么哪種方式更快呢?

讓我們來定義 3 個不同的函數(shù)來連接相同的字符串:

mylist = ["Yang", "Zhou", "is", "writing"]

# 使用'+'
def concat_plus():
    result = ""
    for word in mylist:
        result += word + " "
    return result

# 使用'join()'
def concat_join():
    return " ".join(mylist)

# 直接連接字符串,不使用列表
def concat_directly():
    return "Yang" + "Zhou" + "is" + "writing"

根據(jù)你的第一印象,你認為哪個函數(shù)最快,哪個最慢?

實際結(jié)果可能會讓你驚訝:

import timeit

print(timeit.timeit(concat_plus, number=10000))
# 0.002738415962085128
print(timeit.timeit(concat_join, number=10000))
# 0.0008482920238748193
print(timeit.timeit(concat_directly, number=10000))
# 0.00021425005979835987

如上所示,對于連接一個字符串列表,join()方法比在 for 循環(huán)中逐個添加字符串要快。

原因是直接的。一方面,字符串在 Python 中是不可變數(shù)據(jù),在每次+=操作中都會創(chuàng)建一個新的字符串并復(fù)制舊字符串,這在計算上是昂貴的。

另一方面,.join()方法專門優(yōu)化了字符串的連接。它預(yù)先計算結(jié)果字符串的大小,然后一次性構(gòu)建它。因此,它避免了在循環(huán)中+=操作的開銷,因此它更快。

然而,在我們的測試中最快的函數(shù)是直接連接字符串字面量。它的高速度是由于:

  • Python 解釋器可以在編譯時優(yōu)化字符串字面量的連接,將它們變成單個字符串字面量。沒有循環(huán)迭代或函數(shù)調(diào)用,這使得它是一個非常高效的操作。
  • 由于所有字符串在編譯時都是已知的,Python 可以非??焖俚貓?zhí)行此操作,比循環(huán)中的運行時連接或甚至優(yōu)化的.join()方法都要快得多。

總之,如果你需要連接一個字符串列表,請選擇join()而不是+=。如果你想直接連接字符串,只需使用+即可。

2. 更快的列表創(chuàng)建:使用"[]"而不是"list()"

創(chuàng)建列表不是什么大不了的事。有兩種常見的方式:

  1. 使用list()函數(shù)
  2. 直接使用[]

讓我們使用一個簡單的代碼片段來測試它們的性能:

import timeit

print(timeit.timeit('[]', number=10 ** 7))
# 0.1368238340364769
print(timeit.timeit(list, number=10 ** 7))
# 0.2958830420393497

如結(jié)果所示,執(zhí)行l(wèi)ist()函數(shù)比直接使用[]要慢。

這是因為[]是字面量語法,而list()是一個構(gòu)造函數(shù)調(diào)用。調(diào)用函數(shù)無疑需要額外的時間。

同樣的邏輯,當(dāng)創(chuàng)建字典時,我們也應(yīng)該利用{}而不是dict()。

3. 更快的成員測試:使用集合而不是列表

成員檢查操作的性能在很大程度上取決于底層數(shù)據(jù)結(jié)構(gòu):

import timeit

large_dataset = range(100000)
search_element = 2077

large_list = list(large_dataset)
large_set = set(large_dataset)

def list_membership_test():
    return search_element in large_list

def set_membership_test():
    return search_element in large_set

print(timeit.timeit(list_membership_test, number=1000))
# 0.01112208398990333
print(timeit.timeit(set_membership_test, number=1000))
# 3.27499583363533e-05

如上述代碼所示,集合中的成員測試比列表中的要快得多。

為什么會這樣?

  • 在 Python 列表中,成員測試(element in list)是通過遍歷每個元素直到找到所需元素或到達列表末尾來完成的。因此,此操作的時間復(fù)雜度為 O(n)。
  • Python 中的集合是作為哈希表實現(xiàn)的。當(dāng)檢查成員資格(element in set)時,Python 使用哈希機制,其平均時間復(fù)雜度為 O(1)。

這里的要點是在編寫程序時要仔細考慮底層數(shù)據(jù)結(jié)構(gòu)。利用正確的數(shù)據(jù)結(jié)構(gòu)可以顯著加快我們的代碼速度。

4. 更快的數(shù)據(jù)生成:使用推導(dǎo)式而不是 for 循環(huán)

Python 中有四種類型的推導(dǎo)式:列表、字典、集合和生成器。它們不僅為創(chuàng)建相對數(shù)據(jù)結(jié)構(gòu)提供了更簡潔的語法,而且比使用 for 循環(huán)有更好的性能,因為它們在 Python 的 C 實現(xiàn)中進行了優(yōu)化。

import timeit

def generate_squares_for_loop():
    squares = []
    for i in range(1000):
        squares.append(i * i)
    return squares

def generate_squares_comprehension():
    return [i * i for i in range(1000)]

print(timeit.timeit(generate_squares_for_loop, number=10000))
# 0.2797503340989351
print(timeit.timeit(generate_squares_comprehension, number=10000))
# 0.2364629579242319

上述代碼是列表推導(dǎo)式和 for 循環(huán)之間的簡單速度比較。如結(jié)果所示,列表推導(dǎo)式更快。

5. 更快的循環(huán):優(yōu)先使用局部變量

在 Python 中,訪問局部變量比訪問全局變量或?qū)ο蟮膶傩砸臁?/p>

這里有一個實例來證明這一點:

import timeit

class Example:
    def __init__(self):
        self.value = 0

obj = Example()

def test_dot_notation():
    for _ in range(1000):
        obj.value += 1

def test_local_variable():
    value = obj.value
    for _ in range(1000):
        value += 1
    obj.value = value

print(timeit.timeit(test_dot_notation, number=1000))
# 0.036605041939765215
print(timeit.timeit(test_local_variable, number=1000))
# 0.024470250005833805

這就是 Python 的工作方式。直觀地說,當(dāng)一個函數(shù)被編譯時,里面的局部變量是已知的,但其他外部變量需要時間來檢索。

這是一個小問題,但我們可以利用它來優(yōu)化我們在處理大量數(shù)據(jù)時的代碼。

6. 更快的執(zhí)行:優(yōu)先使用內(nèi)置模塊和庫

當(dāng)工程師們說 Python 時,他們通常指的是 CPython。因為 CPython 是 Python 語言的默認和最廣泛使用的實現(xiàn)。

鑒于其大多數(shù)內(nèi)置模塊和庫都是用 C 語言編寫的,C 是一種更快的低級語言,我們應(yīng)該利用內(nèi)置的武器庫,避免重新發(fā)明輪子。

import timeit
import random
from collections import Counter

def count_frequency_custom(lst):
    frequency = {}
    for item in lst:
        if item in frequency:
            frequency[item] += 1
        else:
            frequency[item] = 1
    return frequency

def count_frequency_builtin(lst):
    return Counter(lst)

large_list = [random.randint(0, 100) for _ in range(1000)]

print(timeit.timeit(lambda: count_frequency_custom(large_list), number=100))
# 0.005160166998393834
print(timeit.timeit(lambda: count_frequency_builtin(large_list), number=100))
# 0.002444291952997446

上述程序比較了兩種計算列表中元素頻率的方法。我們可以看到,利用內(nèi)置的Counter來自collections模塊更快、更整潔、更好。

7. 更快的函數(shù)調(diào)用:利用緩存裝飾器進行簡單的記憶化

緩存是一種常用的技術(shù),用于避免重復(fù)計算并加速程序。

幸運的是,在大多數(shù)情況下,我們不需要編寫自己的緩存處理代碼,因為 Python 為此目的提供了一個現(xiàn)成的裝飾器——@functools.cache。

例如,以下代碼將執(zhí)行兩個斐波那契數(shù)生成函數(shù),一個有緩存裝飾器,另一個沒有:

import timeit
import functools

def fibonacci(n):
    if n in (0, 1):
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

@functools.cache
def fibonacci_cached(n):
    if n in (0, 1):
        return n
    return fibonacci_cached(n - 1) + fibonacci_cached(n - 2)

# 測試每個函數(shù)的執(zhí)行時間
print(timeit.timeit(lambda: fibonacci(30), number=1))
# 0.09499712497927248
print(timeit.timeit(lambda: fibonacci_cached(30), number=1))
# 6.458023563027382e-06

結(jié)果證明了functools.cache裝飾器使我們的代碼更快。

基本的fibonacci函數(shù)效率低下,因為在得到fibonacci(30)的結(jié)果過程中,它多次重新計算相同的斐波那契數(shù)。

緩存版本要快得多,因為它緩存了先前計算的結(jié)果。因此,它只計算一次每個斐波那契數(shù),后續(xù)具有相同參數(shù)的調(diào)用從緩存中檢索。

僅僅添加一個內(nèi)置裝飾器就可以帶來如此大的改進,這就是 Pythonic 的意思。??

8. 更快的無限循環(huán):優(yōu)先選擇 "while 1" 而不是 "while True"

要創(chuàng)建一個無限 while 循環(huán),我們可以使用while True或while 1。

它們性能的差異通??梢院雎圆挥?。但有趣的是,while 1稍微快一點。

這是因為1是字面量,但True是一個需要在 Python 的全局作用域中查找的全局名稱,因此需要一個微小的開銷。

讓我們也在代碼片段中檢查這兩種方式的實際比較:

import timeit

def loop_with_true():
    i = 0
    while True:
        if i >= 1000:
            break
        i += 1

def loop_with_one():
    i = 0
    while 1:
        if i >= 1000:
            break
        i += 1

print(timeit.timeit(loop_with_true, number=10000))
# 0.1733035419601947
print(timeit.timeit(loop_with_one, number=10000))
# 0.16412191605195403

如我們所見,while 1確實稍微快一點。

然而,現(xiàn)代 Python 解釋器(如 CPython)高度優(yōu)化,這種差異通??梢院雎圆挥?。更不用說while True比while 1更易讀。

9. 更快的啟動:智能導(dǎo)入 Python 模塊

在 Python 腳本的頂部導(dǎo)入所有模塊似乎是自然而然的事情。

實際上,我們不必這么做。

此外,如果一個模塊太大,按需導(dǎo)入它是一個更好的主意。

def my_function():
    import heavy_module
    # 函數(shù)的其余部分

如上述代碼,heavy_module在函數(shù)內(nèi)部導(dǎo)入。這是一種“懶加載”的思想,即導(dǎo)入被推遲到my_function被調(diào)用時。

這種方法的好處是,如果my_function在腳本執(zhí)行過程中從未被調(diào)用,那么heavy_module就永遠不會被加載,節(jié)省了資源并減少了腳本的啟動時間。

責(zé)任編輯:武曉燕 來源: 小盒子的技術(shù)分享
相關(guān)推薦

2024-01-08 17:09:07

Python解釋器CPython

2022-01-06 22:31:21

Python技巧代碼

2024-04-29 06:50:45

Python代碼運行

2020-09-04 15:03:18

Python代碼語言

2012-09-11 09:16:52

Hadoop

2023-09-20 00:06:30

Python代碼函數(shù)

2012-09-06 09:36:17

谷歌NatiShalom數(shù)據(jù)處理

2023-12-13 08:28:07

2020-07-08 17:06:00

Python開發(fā)工具

2023-12-29 14:13:41

PyTorch模型開發(fā)

2024-01-26 06:15:44

PythonCPython技巧

2014-08-28 09:35:32

Node.js前端開發(fā)

2024-09-18 05:00:00

Python代碼

2020-08-06 00:25:38

Python代碼開發(fā)

2022-06-22 10:33:06

麻省理工大學(xué)PaShUnix shell

2019-11-25 10:20:54

CSS代碼javascript

2024-08-20 14:25:20

2024-01-19 13:45:00

Pandas代碼深度學(xué)習(xí)

2023-06-26 07:21:41

標(biāo)題欄鼠標(biāo)標(biāo)題

2021-12-14 12:10:41

ChromeWindows瀏覽器
點贊
收藏

51CTO技術(shù)棧公眾號