python 閉包獲取循環數據經典 bug

問題代碼

def create_functions():functions = []for i in range(3):# 創建一個函數,期望捕獲當前循環的i值functions.append(lambda: print(f"My value is: {i}"))return functions# 創建三個函數
f0, f1, f2 = create_functions()# 調用這些函數
f0()  # 期望輸出 "My value is: 0"
f1()  # 期望輸出 "My value is: 1"
f2()  # 期望輸出 "My value is: 2"

但是實際輸出為

My value is: 2
My value is: 2
My value is: 2

類似的,也可以不是用 lambda 表達式,而是使用函數實現閉包

# 依舊有問題
def create_functions():functions = []for i in range(3):def func():print(f"My value is: {i}")functions.append(func)return functions

問題原因解釋

產生這樣問題的原因是:python 閉包捕獲了同一個外部變量 i,并且是通過變量名 i 而非 i 的地址作為索引(這一點很關鍵,雖然實際要比這個復雜,但是可以理解為就是通過名稱確定某個變量的!

  • 如果不是通過變量 i 的字符串名字進行索引,也不會出現這個問題,實際上在 for i in range(3) 過程中給你,i 的地址是一直變的
  • 所以在最后 f0f1f2 都用過名字 i 來找內存,找到了最后的那個 2 對應的內存地址!

兩種解決方案

方案 1:把值通過變量傳進去,此時閉包引用的是 func 的局部變量 x,而每一個函數實際都是不同的

def create_functions():functions = []for i in range(3):def func(x):return lambda: print(f"My value is: {x}")functions.append(func(i))return functions# 創建三個函數
f0, f1, f2 = create_functions()# 調用這些函數
f0()  # 期望輸出 "My value is: 0"
f1()  # 期望輸出 "My value is: 1"
f2()  # 期望輸出 "My value is: 2"

方案 2:使用函數入參默認值,因為 python 在定義函數默認值時,需要計算出來(這也是另外一個經常出 bug 的問題)

def create_functions():functions = []for i in range(3):def func(x=i):print(f"My value is: {x}")functions.append(func)return functions# 創建三個函數
f0, f1, f2 = create_functions()# 調用這些函數
f0()  # 輸出 "My value is: 0"
f1()  # 輸出 "My value is: 1"
f2()  # 輸出 "My value is: 2"

總結

在產生閉包(尤其是 lambda 表達式這種比較隱蔽時)時,一定要注意閉包中對外部變量的引用是否在發生改變,要仔細思考這些改變是否符合預期

不過,只要知道原理,相信可以很好的處理這些情況

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

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

相關文章

克里金模型+多目標優化+多屬性決策!Kriging+NSGAII+熵權TOPSIS!

目錄 效果一覽基本介紹程序設計參考資料 效果一覽 基本介紹 克里金模型多目標優化多屬性決策!KrigingNSGAII熵權TOPSIS!!matlab2023b語言運行! 1.克里金模型(Kriging Model)是一種基于空間統計學的插值方法…

Prompt Engineering 提示詞工程學習

一、Prompt Engineering 簡介 Prompt Engineering 是設計和優化輸入提示(Prompt)以獲得預期輸出的過程。在與大型語言模型(如 GPT-4)交互時,如何構造提示會顯著影響模型的回答質量。 二、Prompt 的重要性 提高生成準確性:通過正確的 Prompt 引導,模型能夠更好地理解用…

MATLAB安裝常見問題及解決方案詳解(含代碼示例)

MATLAB作為科學計算和工程分析的核心工具,其安裝過程可能因操作系統版本、硬件配置或網絡環境等因素而出現各種問題。本文基于MATLAB官方文檔和社區經驗,系統總結了安裝過程中常見的問題,并提供詳細的解決方案和代碼示例,幫助用戶…

免安裝 + 快速響應Photoshop CS6 精簡版低配置電腦修圖

各位PS小白和修圖大神們,今天來給大家聊聊Photoshop CS6精簡版這個寶藏軟件! Photoshop CS6精簡版就是Adobe Photoshop CS6的“瘦身版”,它把一些不常用的功能給簡化了,只留下核心工具,特別適合那些想高效操作、節省系…

微服務架構實戰:從服務拆分到RestTemplate遠程調用

微服務架構實戰:從服務拆分到RestTemplate遠程調用 一 . 服務拆分1.1 服務拆分注意事項1.2 導入服務拆分 Demo1.3 小結 二 . 服務間調用2.1 注冊 RestTemplate2.2 實現遠程調用2.3 小結 三 . 提供方和消費方 在分布式系統設計中,微服務架構因其靈活性、可…

MySQL 索引與事務詳解

目錄 一、索引(Index) 二、事務(Transaction) 三、總結 一、索引(Index) 索引的本質:一種數據結構(如 BTree、Hash),用于快速定位數據,避免全…

macOS Python 環境配置指南

1. 檢查現有 Python 環境 python3 --version # 檢查 Python 3 版本 pip3 --version # 檢查 pip 版本 2. 安裝 pyenv(Python 版本管理工具) # 使用 Homebrew 安裝 pyenvbrew install pyenv# 配置 pyenv 環境變量(添加到 ~/.zshrc&#…

游戲引擎學習第272天:顯式移動轉換

回顧并為今天的內容鋪墊背景 我們剛開始為游戲主角編寫一些程序邏輯,因為我們之前已經完成了大部分引擎方面的開發,現在可以專注在角色身上。這個角色的移動方式會有些特別,與大多數游戲角色的運動機制不太一樣。我們當前正在實現的控制方式…

軟件測試都有什么???

文章目錄 一、白盒測試(結構測試)二、黑盒測試(功能測試)三、灰盒測試四、其他測試類型五、覆蓋準則對比六、應用場景 軟件測試主要根據測試目標、技術手段和覆蓋準則進行分類。分為白盒測試、黑盒測試、灰盒測試及其他補充類型 一…

very_easy_sql(SSRF+SQL注入)

題目有一行提示: you are not an inner user, so we can not let you have identify~(你不是內部用戶,所以我們不能讓你進行身份驗證)聯想到可能存在SSRF漏洞,一般情況下,SSRF攻擊的目標是外網無法訪問的內…

國內外主流AI編程工具全方位對比分析(截至2025年5月)

一、國際主流工具對比 1. Windsurf(Codeium公司) 核心功能:代理型AI編程(代碼導航/修改/命令執行)、瀏覽器DOM訪問、網頁研究功能語言支持:70語言,包括Python/Java/JavaScript/Rust等[[22-23]…

ARP協議的工作原理

文章目錄 ARP協議的工作原理ARP報文(以太網)ARP高速緩存 ARP協議的工作原理 ARP協議的作用是實現任意網絡層地址到任意物理地址轉換。工作原理是: 主機向自己所在網絡廣播一個ARP請求,該請求包含目標機器的網絡地址。處于該網絡…

【小知識酷】《Matlab》考點精簡

在線編譯器 https://matlab.mathworks.com/?elqsidumic49viv8wu5r6fckew 第1章 matlab基礎知識 第1節 輸出函數 1. 使用disp函數 disp函數可用于輸出變量的值或者字符串。 % 輸出字符串 disp(Hello, MATLAB!); %顯示Hello, MATLAB!% 輸出變量 x 10; disp(x); %顯示10% 輸出數…

碼蹄集——中庸之道(三個數比較)

MT1112 中庸之道 請編寫一個簡單程序,輸入3個整數,比較他們的大小,輸出中間的那個數 格式 輸入格式: 輸入整型,空格分隔 輸出格式:輸出整型 樣例 1 輸入:1 5 3 輸出:3 比較…

快速搭建一個vue前端工程

一、環境準備 1、安裝node.js 下載地址:Node.js 推薦版本如下: 2、檢查node.js版本 node -v npm -v 二、安裝Vue腳手架 Vue腳手架是Vue官方提供的標準化開發工具。vue官網:https://cn.vuejs.org/ 全局安裝vue/cli (僅第一次…

React Native基礎環境配置

React Native基礎環境配置 1.引言2.React-Native簡介3.項目基礎環境搭建1.引言 感覺自己掌握的知識面還是有點太窄了,于是決定看看移動端的框架,搞個react搭一個后端管理項目,然后拿react-native寫個小的軟件,試著找個三方上架一下應用市場玩玩。畢竟不可能一直在簡歷上掛一…

PHP和Composer 安裝

Composer 是 PHP 的 依賴管理工具,就像: Node.js 用 npm Python 用 pip Java 用 maven 用來安裝和管理 PHP 項目中需要用到的第三方庫 安裝PHP可以理解成 Java解釋器 安裝PHP PHP For Windows: Binaries and sources Releaseshttps://windows.php.n…

API請求參數有哪些?

通用參數 app_key:應用的唯一標識,用于驗證應用身份,調用API時必須提供。 timestamp:請求時間戳,通常為當前時間的毫秒級時間戳,用于防止請求被重放攻擊。 format:返回數據的格式,…

并發筆記-條件變量(三)

文章目錄 背景與動機30.1 條件變量的定義與基本操作 (Definition and Routines)30.2 生產者/消費者問題 (Bounded Buffer Problem)30.3 覆蓋條件 (Covering Conditions) 與 pthread_cond_broadcast30.4 總結 背景與動機 到目前為止,我們已經學習了鎖 (Locks) 作為并…

stm32實戰項目:無刷驅動

目錄 系統時鐘配置 PWM模塊初始化 ADC模塊配置 霍爾接口配置 速度環定時器 換相邏輯實現 主控制循環 系統時鐘配置 啟用72MHz主頻:RCC_Configuration()設置PLL外設時鐘使能:TIM1/ADC/GPIO時鐘 #include "stm32f10x.h"void RCC_Configu…