Python 閉包:函數式編程中的魔法變量容器

閉包與匿名函數的常見混淆

在編程社區中,閉包(closure)和匿名函數(anonymous function)經常被混為一談,這種混淆有其歷史根源:

  • 歷史發展因素:在早期編程實踐中,在函數內部定義函數并不常見,直到匿名函數廣泛使用后,這種模式才流行起來
  • 概念相關性:只有當涉及嵌套函數時才會出現閉包問題,因此很多開發者是同時接觸這兩個概念的
  • 語法相似性:許多語言中匿名函數的語法形式恰好也是創建閉包的常見方式

關鍵區別:匿名函數關注的是函數的命名方式(沒有標識符),而閉包關注的是函數對環境的捕獲能力(訪問定義體外部的非全局變量)。

閉包的核心定義

閉包是指延伸了作用域的函數,這種函數能夠訪問定義體中引用、但不在定義體中定義的非全局變量。判斷閉包的關鍵要素:

  • 函數不必是匿名的
  • 必須能訪問定義體之外的非全局變量
  • 即使在原始作用域消失后仍能保持這些變量的訪問

深入理解閉包:移動平均值案例

面向對象實現方案

我們先看一個使用類實現的移動平均值計算器:

class Averager():def __init__(self):self.series  = []def __call__(self, new_value):self.series.append(new_value) total = sum(self.series) return total/len(self.series) # 使用方式 
avg = Averager()
print(avg(10))  # 10.0 
print(avg(11))  # 10.5 
print(avg(12))  # 11.0 

這個實現清晰明了:

  • series 存儲在實例屬性 self.series 中
  • 通過實現__call__ 方法使實例可調用
  • 狀態保持直觀可見

函數式閉包實現方案

下面是使用高階函數和閉包的實現方式:

def make_averager():series = []def averager(new_value):series.append(new_value) total = sum(series)return total/len(series)return averager # 使用方式 
avg = make_averager()
print(avg(10))  # 10.0 
print(avg(11))  # 10.5 
print(avg(12))  # 11.0 

這個實現有幾個神奇之處:

  • make_averager() 返回內部函數 averager
  • series 是 make_averager 的局部變量,理論上應在函數結束時消失
  • 但返回的 averager 函數仍然能夠訪問和修改 series

閉包的魔法解析

當調用 make_averager() 時:

  • 創建局部變量 series 并初始化為空列表
  • 定義嵌套函數 averager,它引用了外部變量 series
  • 返回 averager 函數時,Python 會自動捕獲所需的自由變量形成閉包

關鍵點:閉包會保留定義函數時存在的自由變量的綁定,使得在原始作用域消失后仍能使用這些綁定。

閉包的技術實現細節

我們可以通過Python的內省工具來探查閉包的工作機制:

# 查看函數的自由變量和局部變量 
print(avg.__code__.co_varnames)  # ('new_value', 'total')
print(avg.__code__.co_freevars)  # ('series',)# 查看閉包中存儲的具體值 
print(avg.__closure__)  # (<cell at 0x...: list object at 0x...>,)
print(avg.__closure__[0].cell_contents)  # [10, 11, 12]

技術要點解析:

  • code.co_freevars:保存自由變量的名稱元組
  • closure:保存實際的變量綁定(cell對象列表)
  • cell_contents:訪問cell對象中存儲的實際值

閉包的應用價值

  • 狀態保持:在不使用全局變量或類的情況下保持狀態
  • 裝飾器基礎:Python裝飾器的核心實現機制
  • 回調函數:在事件處理中保持上下文
  • 函數工廠:動態生成具有不同行為的函數
  • 延遲計算:捕獲變量供后續計算使用

閉包與類的對比

特性閉包實現類實現
狀態存儲隱式存儲在閉包中顯式存儲在實例屬性中
代碼簡潔性通常更簡潔需要更多樣板代碼
可讀性對不熟悉閉包者較難理解結構清晰,易于理解
擴展性添加新功能較困難通過添加方法容易擴展
性能通常更快方法調用有額外開銷

閉包的高級應用:非局部變量

在Python 3中,我們可以使用 nonlocal 關鍵字顯式聲明自由變量:

def make_counter():count = 0 def counter():nonlocal count count += 1 return count return counter 

nonlocal 聲明表明變量不在當前作用域也不在全局作用域,解決了Python 2中不能修改閉包變量的限制。

閉包的注意事項

  • 內存消耗:閉包會延長捕獲變量的生命周期
  • 循環引用:可能導致意外的內存泄漏
  • 可調試性:閉包中的狀態不如類屬性直觀
  • Python 2限制:不能修改閉包中的變量(除非是可變對象)

總結

閉包是函數式編程中的強大工具,它允許函數捕獲并攜帶其定義環境的部分狀態。理解閉包的關鍵在于認識到函數不僅僅是代碼,還包含其創建時的上下文環境。這種能力使得我們可以編寫更加靈活和表達力強的代碼,特別是在需要保持狀態但又想避免使用全局變量或類的情況下。

閉包的概念雖然在初學階段可能有些難以理解,但一旦掌握,它將大大擴展你解決問題的工具箱,讓你能夠編寫出更加優雅和高效的Python代碼。

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

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

相關文章

迅睿CMS導入別站數據庫

<?php if (isset($_GET[go])) {$host localhost;// 數據庫服務器$username uname;// 數據庫用戶名$password pwd;// 數據庫密碼$database database;// 數據庫名$cmscid $_GET[cmscid];$mtabcid $_GET[mtabcid];if ($_GET[go] step1) {//第一步&#xff1a;先獲取CMS…

基于C++、JsonCpp、Muduo庫實現的分布式RPC通信框架

??個人主頁&#xff1a;小羊 ??所屬專欄&#xff1a;項目 很榮幸您能閱讀我的文章&#xff0c;誠請評論指點&#xff0c;歡迎歡迎 ~ 目錄 項目介紹JsonCpp庫簡單介紹Muduo庫簡單介紹C11異步操作——std::future1. 使用 std::async 關聯異步任務2. std::packaged_task 配…

EPSG:3857 和 EPSG:4326 的區別

EPSG:3857 和 EPSG:4326 是兩種常用的空間參考系統&#xff0c;主要區別在于坐標表示方式和應用場景。以下是它們的核心差異&#xff1a; 1. 坐標系類型 EPSG:4326&#xff08;WGS84&#xff09; 地理坐標系&#xff08;Geographic Coordinate System&#xff09;&#xff0c;基…

Docker 使用與部署(超詳細)

目錄 引入 入門使用 部署對比 鏡像倉庫 命令解釋 基礎 常見命令 示例 數據卷的使用 數據卷的概念 數據卷的使用 掛載本地目錄文件 鏡像 結構 Dockerfile 容器網絡 部署 DockerCompose 語法 ?編輯 基礎命令 引入 當我們在 Linux 上部署一個集成了很多中間件…

JAVA在線考試系統考試管理題庫管理成績查詢重復考試學生管理教師管理源碼

一、源碼描述 這是一套在線考試源碼&#xff0c;基于SpringBootVue框架&#xff0c;后端采用JAVA語言&#xff0c;可以用于重復考試&#xff0c;一、管理員功能&#xff1a;1、考試管理&#xff1a;包括考試查詢與添加考試功能&#xff0c;2、題庫管理&#xff1a;管理所有題庫…

在Qt Creator中使用CUDA

要在Qt Creator項目中使用CUDA進行GPU加速計算&#xff0c;你需要進行一些配置。以下是詳細步驟&#xff1a; 1. 安裝必要軟件 安裝最新版本的NVIDIA CUDA Toolkit 確保已安裝Qt Creator和兼容的編譯器(如MSVC或GCC) 2. 創建Qt項目 打開Qt Creator&#xff0c;創建一個新的…

qml顯示視頻幀(QQuickImageProvider)

一、實現方式 解碼視頻可以選擇:opencv、ffmpeg等。 顯示視頻可以選擇:Qt Multimedia、QQuickImageProvider、ShaderEffect、自定義QQuickItem等。 本文使用opencv解碼視頻,QQuickImageProvider顯示視頻。 二、QQuickImageProvider 中,requestImage 和 requestTexture區…

深度實時美顏:Deep-Live-Cam

深度實時美顏:Deep-Live-Cam 在這個數碼化加速的時代,如何用一張圖片,捕捉瞬間,將虛擬與現實無縫融合在一起?Deep-Live-Cam給出了驚人的答案。這個應用程序不僅實現了實時臉部替換和一鍵視頻深度偽裝,還通過一張圖片完成了這些操作,其獨特的技術讓人在視頻通話和直播中…

OPENGLPG第九版學習 -視口變換、裁減、剪切與反饋

文章目錄 5.1 觀察視圖5.1.1 視圖模型—相機模型OpenGL的整個處理過程中所用到的坐標系統&#xff1a;視錐體視錐體的剪切 5.1.2 視圖模型--正交視圖模型 5.2 用戶變換5.2.1 矩陣乘法的回顧5.2.2 齊次坐標5.2.3 線性變換與矩陣SRT透視投影正交投影 5.2.4 法線變換逐像素計算法向…

卷積神經網絡實戰(2)

接上一篇文章&#xff0c;說到模型定義&#xff1a; class CNN(nn.Module):def __init__(self, activation"relu"):super(CNN, self).__init__()self.activation F.relu if activation "relu" else F.selu#輸入通道數&#xff0c;圖片是灰度圖&#xff…

方案精讀:業財融合轉型路徑和華為實踐【附全文閱讀】

在當今快速變化、競爭激烈的時代,業務面臨不確定性,業財融合至關重要。以華為為例,其從財務到財經的轉型,歷經財務四統一變革、IFS 變革等,構建了包含財經能力中心(COE)、業務伙伴(BP)和財經共享中心(SSC)的財務組織架構 。通過實現財務四算拉通、提升預算預測、項目…

GAF-CNN-SSA-LSSVM故障診斷/分類預測,附帶模型研究報告(Matlab)

GAF-CNN-SSA-LSSVM故障診斷/分類預測&#xff0c;附帶模型研究報告&#xff08;Matlab&#xff09; 目錄 GAF-CNN-SSA-LSSVM故障診斷/分類預測&#xff0c;附帶模型研究報告&#xff08;Matlab&#xff09;效果一覽基本描述程序設計參考資料 效果一覽 基本描述 本研究提出的GA…

新型深度神經網絡架構:ENet模型

語義分割技術能夠為圖像中的每個像素分配一個類別標簽&#xff0c;這對于理解圖像內容和在復雜場景中找到目標對象至關重要。在自動駕駛和增強現實等應用中&#xff0c;實時性是一個硬性要求&#xff0c;因此設計能夠快速運行的卷積神經網絡非常關鍵。 盡管深度卷積神經網絡&am…

基于DGI框架的最佳實踐

基于DGI框架的核心邏輯和搜索結果中的實踐案例&#xff0c;以下是最精簡的5步實施路徑推薦&#xff1a; 1. 明確治理目標與范圍&#xff08;Why & What&#xff09; 聚焦核心問題&#xff1a;優先選擇1-2個業務痛點&#xff08;如數據質量低下、主數據混亂、合規風險&…

使用Prometheus監控網站是否正常打開

要使用普羅米修斯監控你的網站主頁 http://gyq.com/&#xff0c;可以通過以下步驟實現。普羅米修斯本身并不直接支持 HTTP 狀態碼的監控&#xff0c;但可以通過 Blackbox Exporter 來完成這項任務。 方案概述 Blackbox Exporter 是一個普羅米修斯官方提供的工具&#xff0c;用…

基于YOLOv8與LSKNet的遙感圖像旋轉目標檢測新框架 —LSKblock注意力機制在小目標檢測中的性能優化與SOTA探索

針對遙感圖像中目標尺度差異大、方向任意性強、背景復雜度高等挑戰,本文提出一種基于 YOLOv8 與 LSKNet 的新型旋轉目標檢測框架。通過引入 LSKblock 注意力機制 ,實現對多尺度特征的有效建模與動態感受野調整,顯著提升了模型對小目標與旋轉目標的識別能力。 1. 引言 隨著遙…

JVM——JVM 是如何處理異常的?

JVM 是如何處理異常的&#xff1f; 在 Java 編程語言中&#xff0c;異常處理是一種強大的機制&#xff0c;用于應對程序運行時出現的錯誤和意外情況。而 Java 虛擬機&#xff08;JVM&#xff09;作為 Java 程序運行的核心環境&#xff0c;在異常處理過程中扮演著至關重要的角色…

MYSQL三大日志、隔離級別(MVCC+鎖機制實現)

MySQL三大日志 ?Undo Log&#xff08;回滾日志&#xff09; 作用 事務回滾時恢復數據到修改前的狀態。 支持 ??MVCC??&#xff0c;為讀操作提供歷史版本數據。 存儲 存放在 undo tablespace 中&#xff0c;通過回滾段管理。 格式 undo log 格式都有一個 roll_point…

訪問計劃(C++)

題目描述 Farmer John 計劃建造 N&#xff08;1≤N≤10^5&#xff09;個農場&#xff0c;用 N?1 條道路連接&#xff0c;構成一棵樹&#xff08;也就是說&#xff0c;所有農場之間都互相可以到達&#xff0c;并且沒有環&#xff09;。每個農場有一頭奶牛&#xff0c;品種為更…

時間同步服務

時間同步:多主機協作工作時&#xff0c;各個主機的時間同步很重要&#xff0c;時間不一致會造成很多重要應用的故障&#xff0c;如:加密協議&#xff0c;日志&#xff0c;集群等&#xff0c;利用NTP(Network Time Protocol )協議使網絡中的各個計算機 時間達到同步。目前NTP協議…