閉包和裝飾器

什么是閉包

閉包(Closure)是 Python 中一個非常重要的概念,它是一種特殊的函數對象,通常用于封裝和延遲計算某些值。以下是閉包的詳細定義和解釋:

1.閉包的定義
閉包是指一個函數對象,它不僅包含函數的代碼,還綁定了函數外部的自由變量(free variable)。自由變量是指在函數內部被引用,但不是函數參數的變量。閉包允許函數訪問和操作這些自由變量,即使這些變量的作用域已經結束。

2.閉包的構成要素
一個閉包通常由以下三個部分組成:

? 外部函數:定義了自由變量的函數。

? 內部函數:在外部函數內部定義的函數,它引用了外部函數的自由變量。

? 自由變量:在內部函數中被引用,但不是內部函數參數的變量。

3.閉包的創建
閉包是通過返回內部函數來創建的。當內部函數被返回時,它會記住外部函數的自由變量,即使外部函數的作用域已經結束。這種機制使得閉包可以“記住”外部函數的上下文。

4.閉包的作用
閉包的主要作用是封裝狀態,允許函數在不使用全局變量的情況下,保存和操作一些數據。閉包可以用于實現裝飾器、延遲計算、回調函數等功能。

5.閉包的示例
以下是一個簡單的閉包示例,用于說明閉包的創建和使用:

def outer_function(x):def inner_function(y):return x + y  # x 是自由變量return inner_function  # 返回內部函數,創建閉包# 創建閉包
closure = outer_function(10)  # x 被綁定為 10# 調用閉包
result = closure(5)  # 調用 inner_function,y 為 5,結果為 15
print(result)  # 輸出 15

在這個例子中:

? outer_function是外部函數,它定義了一個自由變量x

? inner_function是內部函數,它引用了自由變量x

? 當outer_function被調用時,它返回了inner_function,此時inner_function記住了x的值(10),即使outer_function的作用域已經結束。

? closure是一個閉包對象,它綁定了自由變量x的值(10),并可以被多次調用。

6.閉包的特性

? 自由變量的綁定:閉包會記住外部函數的自由變量的值,即使外部函數的作用域已經結束。

? 延遲計算:閉包允許延遲計算某些值,直到內部函數被調用。

? 封裝性:閉包可以封裝狀態,避免使用全局變量,使代碼更加模塊化。

7.閉包的應用場景

? 裝飾器:Python 中的裝飾器本質上是閉包,用于在不修改原函數的情況下擴展函數的功能。

? 回調函數:閉包可以作為回調函數,保存一些上下文信息。

? 延遲計算:閉包可以用于延遲計算某些值,直到需要時才計算。

? 封裝狀態:閉包可以封裝一些狀態信息,避免使用全局變量。

8.注意事項

? 內存占用:閉包會占用一定的內存,因為它們需要保存自由變量的值。

? 變量作用域:自由變量的值是綁定在閉包創建時的值,而不是調用時的值。

? 不可變變量:如果自由變量是不可變類型(如整數、字符串等),它們的值在閉包中是固定的;如果是可變類型(如列表、字典等),它們的值可以在閉包中被修改。

全局變量使用

在 Python 中,nonlocal是一個關鍵字,用于在嵌套函數中修改外部函數(但不是全局作用域)中的變量。它是 Python 3 中引入的一個特性,用于解決嵌套函數中變量作用域的問題。

1.nonlocal的作用

在嵌套函數中,如果內部函數需要修改外部函數中的變量,而這個變量既不是全局變量,也不是內部函數的局部變量,那么就需要使用nonlocal關鍵字。nonlocal告訴 Python,變量來自外層作用域(但不是全局作用域),從而允許內部函數修改這個變量。

2.使用場景

假設有一個外部函數和一個內部函數,外部函數中定義了一個變量,內部函數需要修改這個變量。如果沒有nonlocal,Python 會認為內部函數中對變量的賦值是創建了一個新的局部變量,而不是修改外部函數中的變量。使用nonlocal可以明確告訴 Python,要修改的是外部函數中的變量。

3.示例

以下是一個使用nonlocal的示例:

def outer_function():x = 10  # 外部函數中的變量def inner_function():nonlocal x  # 使用 nonlocal 聲明 xx = 20  # 修改外部函數中的 xinner_function()  # 調用內部函數print(x)  # 輸出修改后的 xouter_function()

輸出結果為:

20

在這個例子中:

? xouter_function中的局部變量。

? inner_function是嵌套在outer_function內部的函數。

? 如果不使用nonlocalinner_function中的x = 20會創建一個新的局部變量x,而不會修改outer_function中的x

? 使用nonlocal x后,inner_function中的x = 20會修改outer_function中的x

4.nonlocal的規則

? nonlocal只能用于嵌套函數中,不能用于全局作用域。

? nonlocal聲明的變量必須在外部作用域中已經存在,不能在內部函數中直接創建一個nonlocal變量。

? nonlocal只能用于修改變量的值,不能用于重新綁定變量到一個新的對象。

5.示例:嵌套多層函數

nonlocal可以用于多層嵌套的函數中,但只能作用于直接外層的變量。例如:

def outer_function():x = 10def middle_function():def inner_function():nonlocal x  # 修改 outer_function 中的 xx = 20inner_function()middle_function()print(x)outer_function()

輸出結果為:

20

在這個例子中,inner_function中的nonlocal x修改了outer_function中的x,而不是middle_function中的x

7.nonlocalglobal的區別

? global用于聲明全局變量,可以在函數內部修改全局作用域中的變量。

? nonlocal用于聲明嵌套函數中的變量,只能修改外層函數(非全局作用域)中的變量。

閉包的主要作用就是使用裝飾器

裝飾器(Decorator)是Python提供的一種語法糖,它允許你在不修改函數本身代碼的情況下,增加函數的新功能。裝飾器本質上是一個函數,它接收一個函數作為參數并返回一個新的函數。

裝飾器的功能特點:

  1. 不修改已有函數的源代碼:裝飾器不會改變被裝飾函數的代碼。

  2. 不修改已有函數的調用方式:調用被裝飾的函數時,不需要改變調用方式。

  3. 給已有函數增加額外的功能:裝飾器可以在不修改函數代碼的情況下,給函數增加新的功能。

裝飾器的使用:
由于裝飾器本質上就是一個閉包函數,所以在使用自定義裝飾器之前,需要先定義一個用來做裝飾器的閉包。閉包的外部函數名,就作為裝飾器名使用。

在圖中,展示了一個簡單的裝飾器示例:

import timedef count_time(func):def inner():start_time = time.time()func()stop_time = time.time()print(f"Function {func.__name__} took {stop_time - start_time} seconds to execute.")return inner# 使用裝飾器
@count_time
def example_function():time.sleep(2)print("Function is running.")

在這個例子中:

? count_time是一個裝飾器函數,它接收一個函數func作為參數,并返回一個新的函數inner

? inner函數記錄了func函數的執行時間,并在執行前后打印相關信息。

? @count_time是裝飾器的使用方式,它將example_function函數作為參數傳遞給count_time裝飾器。

通過這種方式,example_function在執行時會自動記錄并打印其執行時間,而不需要修改example_function的代碼。這就是裝飾器的強大之處,它能夠在不改變函數代碼的情況下,給函數增加新的功能。

可變參數

在Python中,如果你需要定義一個函數來處理可變數量的參數,你可以使用*args**kwargs來實現。這兩種方法允許你的函數接收任意數量的位置參數和關鍵字參數。

使用*args處理可變數量的位置參數

*args允許你將任意數量的位置參數傳遞給函數,這些參數在函數內部作為一個元組處理。

def fun(*args):for arg in args:print(arg)fun(1, 2, 3, 4, 5)  # 輸出: 1 2 3 4 5

在這個例子中,fun函數可以接收任意數量的位置參數,并將它們打印出來。

使用**kwargs處理可變數量的關鍵字參數

**kwargs允許你將任意數量的關鍵字參數傳遞給函數,這些參數在函數內部作為一個字典處理。

def fun(**kwargs):for key, value in kwargs.items():print(f"{key}: {value}")fun(name="Alice", age=25, city="New York")  # 輸出: name: Alice age: 25 city: New York

在這個例子中,fun函數可以接收任意數量的關鍵字參數,并將它們打印出來。

結合使用*args**kwargs

你可以在同一個函數中同時使用*args**kwargs,以處理任意數量的位置參數和關鍵字參數。

def fun(*args, **kwargs):for arg in args:print(arg)for key, value in kwargs.items():print(f"{key}: {value}")fun(1, 2, 3, name="Alice", age=25)  # 輸出: 1 2 3 name: Alice age: 25

在這個例子中,fun函數可以同時接收任意數量的位置參數和關鍵字參數。

裝飾器中使用*args**kwargs

當你在裝飾器中處理被裝飾函數時,如果被裝飾函數可能接收可變數量的參數,你需要在裝飾器的包裝函數中傳遞這些參數。

import timedef count_time(func):def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)end_time = time.time()print(f"Function {func.__name__} took {end_time - start_time} seconds to execute.")return resultreturn wrapper@count_time
def greet(name, *args, **kwargs):print(f"Hello, {name}!")for arg in args:print(arg)for key, value in kwargs.items():print(f"{key}: {value}")greet("Alice", 25, city="New York")  # 輸出: Hello, Alice! 25 city: New York

在這個例子中,greet函數可以接收一個位置參數name,任意數量的位置參數*args,以及任意數量的關鍵字參數**kwargs。裝飾器count_time通過在包裝函數wrapper中使用*args**kwargs,確保了這些參數能夠正確地傳遞給greet函數。

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

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

相關文章

notepad++8.6.4安裝及細節

notepad8.6.4下載安裝(附安裝包) 一、安裝包下載1.1方法一:官網下載(點擊跳轉)1.2方法二:網盤鏈接分享8.6.4版本 二、安裝過程細節2.1這里的組件建議全部勾選。點擊“下一步”。2.2 勾選①:可以…

COZE通關指南:工作流與插件開發

前言 本文隸屬于專欄《AI Agent 通關指南》,該專欄為筆者原創,引用請注明來源,不足和錯誤之處請在評論區幫忙指出,謝謝! 本專欄目錄結構和參考文獻請見《AI Agent 通關指南》 正文 1. 平臺基礎介紹 ?? 1.1 COZE平臺概述 COZE平臺(coze.cn)是一個強大的AI應用開發平臺…

【Block總結】ENLTransformerBlock,高效非局部變換器塊|即插即用

1. 論文信息 標題: Perspective+ Unet: Enhancing Segmentation with Bi-Path Fusion and Efficient Non-Local Attention for Superior Receptive Fields論文地址: arXiv:2406.14052 2. 創新點 雙路徑編碼策略: 在編碼器階段引入雙路徑策略,結合傳統卷積和空洞卷積的結果,平…

【爬蟲】網易云音樂評論數據爬取

文章目錄 🍖 前言🎶一、抓取要求?二、代碼展示🏀三、運行結果🏆四、知識點提示 🍖 前言 【爬蟲】網易云音樂歌詞/評論數據爬取 🎶一、抓取要求 描述: 輸入歌曲的id,獲取對應歌曲的用戶評論信…

C++使用Qt Charts創建數據可視化圖表

Qt Charts 是一個強大的工具,用于創建直觀的數據可視化圖表。本文將通過一個具體的示例,展示如何使用 Qt Charts 創建一個包含多條數據序列、自定義坐標軸和隨機數據生成的圖表。 示例代碼解析 以下是一個完整的示例代碼,展示如何使用 Qt Ch…

TCP/IP五層協議

目錄 1. 五層模型結構 2. 各層核心功能與協議 (1) 應用層(Application Layer) (2) 傳輸層(Transport Layer) (3) 網絡層(Network Layer) (4) 數據鏈路層(Data Link Layer) (5…

【最新版】金媒婚戀系統v10.5最新穩定開源+原生前端小程序 PC端+安裝教程

一.系統簡介 1. 紅娘服務 紅娘服務模塊是該系統的一大特色。專業紅娘會通過分析用戶的個人資料和偏好, 為用戶提供精準的配對建議和個性化服務。用戶可以預約紅娘服務,通過紅娘的介入,提升配對成功率。 2. 相親活動 相親活動模塊用于組織和管…

吳恩達深度學習復盤(5)神經網絡的前向傳播TesorFlow與NumPy實現比對

數據結構差別 NumPy 和 TensorFlow 在數據表示上的差異展開,結合神經網絡實踐中的常見問題進行說明。以下是詳細解析: 一、簡介 數據表示的歷史背景 NumPy 是 Python 科學計算的基礎庫,早期設計為處理多維數組TensorFlow 由 Google Brain 團…

多元高斯分布函數

1、 n n n元向量 假設 n n n元隨機變量 X X X X [ X 1 , X 2 , ? , X i , ? , X n ] T μ [ μ 1 , μ 2 , ? , μ i , ? , μ n ] T σ [ σ 1 , σ 2 , ? , σ i , ? , σ n ] T X i ~ N ( μ i , σ i 2 ) \begin{split} X&[X_1,X_2,\cdots,X_i,\cdots ,X_n…

洞察 Linux 進程管理

一、進程和線程的概念 1.進程 (1)概念 進程是程序在操作系統中的一次執行過程,是系統進行資源分配和調度的基本單位。進程是程序的執行實例,擁有獨立的資源(如內存、文件描述符等)。每個進程在創建時會被…

PyTorch 實現圖像版多頭注意力(Multi-Head Attention)和自注意力(Self-Attention)

本文提供一個適用于圖像輸入的多頭注意力機制(Multi-Head Attention)PyTorch 實現,適用于 ViT、MAE 等視覺 Transformer 中的注意力計算。 模塊說明 輸入支持圖像格式 (B, C, H, W)內部轉換為序列 (B, N, C),其中 N H * W多頭注…

每日一題(小白)字符串娛樂篇16

分析題意可以了解到本題要求在一串字符串中找到所有組合起來排序遞增的字符串。我們可以默認所有字符在字符串中的上升序列是1,從第一個字符開始找,如果后面的字符大于前面的字符就說明這是一個上序列那么后面字符所在的數組加一,如果連接不上…

Ubuntu 22 Linux上部署DeepSeek R1保姆式操作詳解(Xinference方式)

一、安裝步驟 1.基礎環境安裝 安裝顯卡驅動、cuda,根據自己硬件情況查找相應編號,本篇不介紹這部分內容,只給出參考指令,詳情請讀者自行查閱互聯網其它參考資料。 sudo apt install nvidia-utils-565-server sudo apt install…

Immutable.js 完全指南:不可變數據的藝術與實踐

引言 在現代前端開發中,狀態管理是一個核心挑戰。隨著應用復雜度增加,如何高效、安全地管理應用狀態變得至關重要。Immutable.js 是 Facebook 推出的一個 JavaScript 庫,它提供了持久化不可變數據結構,可以幫助開發者更好地管理應…

字符串數據類型的基本運算

任務描述 本關任務:從后臺輸入任意三個字符串,求最大的字符串。 相關知識 字符串本身是存放在一塊連續的內存空間中,并以’\0’作為字符串的結束標記。 字符指針變量本身是一個變量,用于存放字符串的第 1 個字符的地址。 字符數…

Ubuntu 22.04 一鍵部署openManus

openManus 前言 OpenManus-RL,這是一個專注于基于強化學習(RL,例如 GRPO)的方法來優化大語言模型(LLM)智能體的開源項目,由來自UIUC 和 OpenManus 的研究人員合作開發。 前提要求 安裝deepseek docker方式安裝 ,windows 方式安裝,Linux安裝方式

PDF 轉圖片,一行代碼搞定!批量支持已上線!

大家好,我是程序員晚楓。今天我要給大家帶來一個超實用的功能——popdf 現在支持 PDF 轉圖片了,而且還能批量操作!是不是很激動?別急,我來手把手教你玩轉這個功能。 1. 一行代碼搞定單文件轉換 popdf 的核心就是簡單暴…

《比特城的機密郵件:加密、簽名與防篡改的守護之戰》

點擊下面圖片帶您領略全新的嵌入式學習路線 🔥爆款熱榜 88萬閱讀 1.6萬收藏 第一章:風暴前的密令 比特城的議會大廳內,首席長老艾德文握著一卷足有半人高的羊皮紙,眉頭緊鎖。紙上是即將頒布的《新紀元法典》——這份文件不僅內…

8.用戶管理專欄主頁面開發

用戶管理專欄主頁面開發 寫在前面用戶權限控制用戶列表接口設計主頁面開發前端account/Index.vuelangs/zh.jsstore.js 后端Paginator概述基本用法代碼示例屬性與方法 urls.pyviews.py 運行效果 總結 歡迎加入Gerapy二次開發教程專欄! 本專欄專為新手開發者精心策劃了…

http://noi.openjudge.cn/_2.5基本算法之搜索_1804:小游戲

文章目錄 題目深搜代碼寬搜代碼深搜數據演示圖總結 題目 1804:小游戲 總時間限制: 1000ms 內存限制: 65536kB 描述 一天早上,你起床的時候想:“我編程序這么牛,為什么不能靠這個賺點小錢呢?”因此你決定編寫一個小游戲。 游戲在一…