9 個讓 Python 性能更高的小技巧,你掌握了嗎?

我們經常聽到 “Python 太慢了”,“Python 性能不行”這樣的觀點。但是,只要掌握一些編程技巧,就能大幅提升 Python 的運行速度。

今天就讓我們一起來看下讓 Python 性能更高的 9 個小技巧

python學習資料分享(無償):

在這里插入圖片描述

字符串拼接的技巧

如果有大量字符串等待處理,字符串連接將成為 Python 的瓶頸。

一般來講,Python 中有兩種字符串拼接方式:

  • 使用該 join() 函數將字符串列表合并為一個字符串
  • 使用 + or += 符號將每個字符串加成一個

那么哪種方式更快呢?我們一起來看一下

mylist = ["Yang", "Zhou", "is", "writing"]# Using '+'
def concat_plus():result = ""for word in mylist:result += word + " "return result# Using 'join()'
def concat_join():return " ".join(mylist)# Directly concatenation without the list
def concat_directly():return "Yang" + "Zhou" + "is" + "writing"
import timeitprint(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 循環中逐個添加字符串更快。

原因很簡單。一方面,字符串是 Python 中的不可變數據,每個 += 操作都會導致創建一個新字符串并復制舊字符串,這會導致非常大的開銷。

另一方面,.join() 方法是專門為連接字符串序列而優化的。它預先計算結果字符串的大小,然后一次性構建它。因此,它避免了與循環中 += 操作相關的開銷,因此速度更快。

但是,我們發現最快其實是直接用 + 拼接字符串,這是因為:

  • Python 解釋器可以在編譯時優化字符串的連接,將它們轉換為單個字符串。因為沒有循環迭代或函數調用,所以它是一個非常高效的操作。
  • 由于所有字符串在編譯時都是已知的,因此 Python 可以非常快速地執行此操作,比循環中的運行時連接甚至優化 .join() 方法快得多。

總之,如果需要拼接字符串列表,請選擇 join() ;如果直接拼接字符串,只需使用 + 即可。

創建列表的技巧

Python 中創建列表的兩種常見方法是:

  • 使用函數 list()
  • [] 直接使用

我們來看下這兩種方法的性能

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

結果表明,執行 list() 函數比直接使用 [] 要慢。

這是因為 是 [] 字面語法( literal syntax ),而 list() 是構造函數調用。毫無疑問,調用函數需要額外的時間。

同理,在創建字典時,我們也應該利用 {} 而不是 dict()

成員關系測試的技巧

成員關系測試的性能很大程度上取決于底層數據結構

import timeitlarge_dataset = range(100000)
search_element = 2077large_list = list(large_dataset)
large_set = set(large_dataset)def list_membership_test():return search_element in large_listdef set_membership_test():return search_element in large_setprint(timeit.timeit(list_membership_test, number=1000))
# 0.01112208398990333
print(timeit.timeit(set_membership_test, number=1000))
# 3.27499583363533e-05

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

這是為什么呢?

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

這里的技巧重點是在編寫程序時仔細考慮底層數據結構。利用正確的數據結構可以顯著加快我們的代碼速度。

使用推導式而不是 for 循環

Python 中有四種類型的推導式:列表、字典、集合和生成器。它們不僅為創建相對數據結構提供了更簡潔的語法,而且比使用 for 循環具有更好的性能。

因為它們在 Python 的 C 實現中進行了優化。

import timeitdef generate_squares_for_loop():squares = []for i in range(1000):squares.append(i * i)return squaresdef 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

上面的代碼是列表推導式和 for 循環之間的簡單速度比較。如結果所示,列表推導式速度更快。

訪問局部變量速度更快

在 Python 中,訪問局部變量比訪問全局變量或對象的屬性更快。

import timeitclass Example:def __init__(self):self.value = 0obj = Example()def test_dot_notation():for _ in range(1000):obj.value += 1def test_local_variable():value = obj.valuefor _ in range(1000):value += 1obj.value = valueprint(timeit.timeit(test_dot_notation, number=1000))
# 0.036605041939765215
print(timeit.timeit(test_local_variable, number=1000))
# 0.024470250005833805

原理也很簡單:當編譯一個函數時,它內部的局部變量是已知的,但其他外部變量需要時間來檢索。

優先考慮內置模塊和庫

當我們討論 Python 的時候,通常指的是 CPython,因為 CPython 是 Python 語言的默認和使用最廣泛的實現。

考慮到它的大多數內置模塊和庫都是用C語言編寫的,C語言是一種更快、更低級的語言,我們應該利用它的內置庫,避免重復造輪子。

import timeit
import random
from collections import Counterdef count_frequency_custom(lst):frequency = {}for item in lst:if item in frequency:frequency[item] += 1else:frequency[item] = 1return frequencydef 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

上面的程序比較了計算列表中元素頻率的兩種方法。正如我們所看到的,利用 collections 模塊的內置計數器比我們自己編寫 for 循環更快、更簡潔、更好。

使用緩存裝飾器

緩存是避免重復計算和提高程序速度的常用技術。

幸運的是,在大多數情況下,我們不需要編寫自己的緩存處理代碼,因為 Python 提供了一個開箱即用的裝飾器 — @functools.cache

例如,以下代碼將執行兩個斐波那契數生成函數,一個具有緩存裝飾器,但另一個沒有:

import timeit
import functoolsdef fibonacci(n):if n in (0, 1):return nreturn fibonacci(n - 1) + fibonacci(n - 2)@functools.cache
def fibonacci_cached(n):if n in (0, 1):return nreturn fibonacci_cached(n - 1) + fibonacci_cached(n - 2)# Test the execution time of each function
print(timeit.timeit(lambda: fibonacci(30), number=1))
# 0.09499712497927248
print(timeit.timeit(lambda: fibonacci_cached(30), number=1))
# 6.458023563027382e-06

可以看到 functools.cache 裝飾器如何使我們的代碼運行得更快。

緩存版本的速度明顯更快,因為它緩存了先前計算的結果。因此,它只計算每個斐波那契數一次,并從緩存中檢索具有相同參數的后續調用

while 1 VS while True

如果要創建無限 while 循環,我們可以使用 while True or while 1 .

它們的性能差異通常可以忽略不計。但有趣的是, while 1 稍微快一點。

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

import timeitdef loop_with_true():i = 0while True:if i >= 1000:breaki += 1def loop_with_one():i = 0while 1:if i >= 1000:breaki += 1print(timeit.timeit(loop_with_true, number=10000))
# 0.1733035419601947
print(timeit.timeit(loop_with_one, number=10000))
# 0.16412191605195403

正如我們所看到的,確實 while 1 稍微快一些。

然而,現代 Python 解釋器(如 CPython )是高度優化的,這種差異通常是微不足道的。所以我們不需要擔心這個可以忽略不計的差異。更不用說 while Truewhile 1 可讀性更好。

按需導入 Python 模塊

在 Python 腳本開頭導入所有模塊似乎是每個人都會這么做的操作,事實上我們沒有必要導入全部的模塊。如果模塊太大,則根據需要導入它是一個更好的主意。

def my_function():import heavy_module# rest of the function

如上面的代碼所示,heavy_module 在函數中導入。這是一種“延遲加載”的思想:只有 my_function 被調用的時候該模塊才會被導入。

這種方法的好處是,如果 my_function 在腳本執行期間從未調用過,則 heavy_module 永遠不會加載,從而節省資源并減少腳本的啟動時間。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/43982.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/43982.shtml
英文地址,請注明出處:http://en.pswp.cn/web/43982.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據(圖像)增廣

一、數據增強 1、增加一個已有數據集,使得有更多的多樣性,比如加入不同的背景噪音、改變圖片的顏色和形狀。 2、增強數據是在線生成的 3、增強類型: (1)翻轉 (2)切割 (3&#xf…

金龍魚:只是躺槍?

中儲糧罐車運輸油罐混用事件持續發酵,食用油板塊集體躺槍。 消費者憤怒的火,怕是會讓食用油企們一點就著。 今天,我們聊聊“油”茅——金龍魚。 一邊是業內人士指出,油罐混用的現象普遍存在,另一邊是金龍魚回應稱&am…

2972.力扣每日一題7/11 Java(擊敗100%)

博客主頁:音符猶如代碼系列專欄:算法練習關注博主,后期持續更新系列文章如果有錯誤感謝請大家批評指出,及時修改感謝大家點贊👍收藏?評論? 目錄 解題思路 解題方法 時間復雜度 空間復雜度 Code 解題思路 該問…

RISC-V主要指令集介紹及規則

推薦資料 RISC-V Reader / RISC-V開放架構設計之道,適合新手閱讀。 概述 RISC-V的模塊化到底是如何實現的呢? 核心部分:RV32I,代表32位字長的整型指令集(Integer),包含了許多整型指令如load…

在C++項目中添加錄像功能:從攝像頭捕獲到視頻文件的保存

在C項目中添加錄像功能:從攝像頭捕獲到視頻文件的保存 在這篇博客中,我們將介紹如何在一個現有的C項目中添加錄像功能,具體包括如何從攝像頭捕獲圖像并將其保存為視頻文件。我們將使用OpenCV庫來處理圖像捕獲和視頻寫入。 目錄 引言準備工…

Python學習筆記35:進階篇(二十四)pygame的使用之音頻文件播放

前言 基礎模塊的知識通過這么長時間的學習已經有所了解,更加深入的話需要通過完成各種項目,在這個過程中逐漸學習,成長。 我們的下一步目標是完成python crash course中的外星人入侵項目,這是一個2D游戲項目。在這之前&#xff…

元組列表之案例

1.列表推導式 基本語法: [表達式 for語句1 if 語句1 for語句2 if語句2 ........ ] 1.零到九的平方列表 a [i*i for i in range(10)] print(a) 2.for 循環前面加if else #如果是偶數乘以2,如果是奇數直接輸出 a [i*2 if i%2 0 else i for i in ran…

什么是生成器函數?

生成器函數(Generator Function)是 JavaScript 中一種特殊的函數,它可以在執行過程中暫停并在之后恢復執行。生成器函數使用 function* 語法定義,并且內部使用 yield 表達式來暫停函數執行并返回一個值。每次調用生成器函數返回的…

rabbitmq集群創建admin用戶之后,提示can access virtual hosts是No access狀態

問題描述: 因業務需要使用的rabbitmq是3.7.8版本的,rabbitmq在3.3.0之后就允許使用guest賬號的權限了,所以需要創建一個administrator標簽的用戶。 如下操作創建的用戶: 創建完成之后就提示如下的報錯: 注&#xff1a…

php表單提交并自動發送郵件給某個郵箱(示例源碼下載)

只需要將以下代碼內容進行復制即可用到自己的程序/API接口中&#xff1a; <?php if(!empty($_POST[is_post]) && $_POST[is_post]1){$url "https://www.aoksend.com/index/api/send_email";$name $_POST[name];$email $_POST[email];$subject $_POS…

探索Mojo模型:解鎖機器學習模型的可解釋性之旅

探索Mojo模型&#xff1a;解鎖機器學習模型的可解釋性之旅 在人工智能和機器學習領域&#xff0c;模型的可解釋性是一個至關重要的議題。隨著模型變得越來越復雜&#xff0c;理解模型的決策過程成為了一個挑戰。Mojo模型作為一種模型序列化格式&#xff0c;提供了一種方法來部…

Python 給存入 Redis 的鍵值對設置過期時間

Redis 是一種內存中的數據存儲系統&#xff0c;與許多傳統數據庫相比&#xff0c;它具有一些優勢&#xff0c;其中之一就是可以設置數據的過期時間。通過 Redis 的過期時間設置&#xff0c;可以為存儲在 Redis 中的數據設置一個特定的生存時間。一旦數據到達過期時間&#xff0…

mybatis日志記錄方案

首先對指定表進行監控 對表進行監控,那么就要使用的是statementInterceptor 攔截器 使用攔截器那么就要寫intercepts寫攔截條件進行攔截 監控只對與增刪改 查詢不進行監控 對于字段的監控,是誰修改了字段,那么就進行報警,或者提醒 消息提醒使用釘釘機器人進行消息提醒 P…

軟鏈接node_modules

公司項目很多微應用的子項目公用同一套模板&#xff0c;也就會使用同一個node_modules 1.先創建3個同樣的項目,并安裝一個其中的一個node_modules給他丟到外邊 2.win r -------> cmd --------> ctrlshift enter(已管理員身份打開cmd) 3.在窗口分別執行以下代碼…

視頻減小技巧:十大頂級視頻壓縮軟件

視頻壓縮軟件會盡可能地壓縮視頻&#xff0c;以便上傳到各個網站。通常&#xff0c;4K 或更高質量的視頻體積更大。壓縮軟件有助于壓縮體積。在這里&#xff0c;我們來討論一下 10 款最佳視頻壓縮軟件。 十大頂級視頻壓縮軟件 1. 奇客壓縮寶 奇客壓縮寶是由Geekersoft公司開發…

基于SpringBoot+MySQL的租房項目+文檔

&#x1f497;博主介紹&#x1f497;&#xff1a;?在職Java研發工程師、專注于程序設計、源碼分享、技術交流、專注于Java技術領域和畢業設計? 溫馨提示&#xff1a;文末有 CSDN 平臺官方提供的老師 Wechat / QQ 名片 :) Java精品實戰案例《700套》 2025最新畢業設計選題推薦…

數據庫系統中的Undo和Redo

在數據庫管理系統&#xff08;DBMS&#xff09;中&#xff0c;undo 和 redo 是兩種用于事務管理和故障恢復的重要機制。它們主要涉及事務的提交、回滾以及系統故障后的數據恢復。 Undo&#xff08;撤銷&#xff09; 作用&#xff1a;undo 用于撤銷未提交事務所做的修改&#…

極狐Gitlab使用(1)

目錄 續接上篇&#xff1a;極狐Gitlab安裝部署-CSDN博客 1. 關閉注冊功能 2. 創建群組 3. 創建用戶 5. 邀請成員到群組 6. 設置導入導出項目源 7. 通過gitee導入庫 8. 通過倉庫URL導入 9. 自創建項目 10. 默認分支main的權限 11. 使用普通用戶進入自建庫 12. 創建用…

java的遍歷的方法對比 效率對比

在 Java 中&#xff0c;遍歷對象的方式主要取決于對象的類型和數據結構。以下是幾種常見的遍歷方式&#xff0c;以及它們的效率比較&#xff1a; 普通的 for 循環&#xff1a; 效率&#xff1a;高。使用普通的 for 循環可以直接根據索引來訪問元素&#xff0c;適用于數組和實現…

Ubuntu系統上安裝Apache和WordPress

** 第一步跟新系統包 ** 首先跟新系統包 sudo apt update sudo apt upgrade第二步下載安裝apache sudo apt install apache2 ##查看apache的狀態是否啟動成功 sudo systemctl status apache2 ##查看服務器的ip地址 sudo ip a通過ip地址進行訪問apache頁面 第三步下載安裝…