目錄
類別屬性/方法
描述子協定
為什麼self在方法定義中?
首頁 後端開發 Python教學 Python中的self參數是什麼?

Python中的self參數是什麼?

May 08, 2023 pm 05:49 PM
python elf

Python 的"self"参数是什么?

讓我們從我們已經知道的開始:self - 方法中的第一個參數- 指的是類別實例:

class MyClass:
┌─────────────────┐
▼ │
def do_stuff(self, some_arg): │
print(some_arg)▲│
 ││
 ││
 ││
 ││
instance = MyClass() ││
instance.do_stuff("whatever") │
│ │
└───────────────────────────────┘
登入後複製

此外,這個論點實際上不必稱為self - 它只是一個約定。例如,你可以像其他語言中常見的那樣使用它。

上面的程式碼可能是自然而明顯的,因為你一直在使用,但是我們只給了.do_stuff() 一個參數(some_arg),但該方法聲明了兩個(self 和, some_arg) ,好像也說不通。片段中的箭頭顯示 self 被翻譯成實例,但它是如何真正傳遞的呢?

instance = MyClass()
MyClass.do_stuff(instance, "whatever")
登入後複製

Python 在內部所做的是將 instance.do_stuff("whatever") 轉換為 MyClass.do_stuff(instance, "whatever")。我們可以在這裡稱之為“Python 魔法”,但如果我們想真正了解幕後發生的事情,我們需要了解 Python 方法是什麼以及它們與函數的關係。

類別屬性/方法

在 Python 中,沒有「方法」物件之類的東西——實際上方法只是常規函數。函數和方法之間的區別在於,方法是在類別的命名空間中定義的,使它們成為該類別的屬性。

這些屬性儲存在類別字典__dict__ 中,我們可以直接存取或使用vars 內建函數存取:

MyClass.__dict__["do_stuff"]
# <function MyClass.do_stuff at 0x7f132b73d550>
vars(MyClass)["do_stuff"]
# <function MyClass.do_stuff at 0x7f132b73d550>
登入後複製

存取它們的最常見方法是「類別方法」方式:

print(MyClass.do_stuff)
# <function MyClass.do_stuff at 0x7f132b73d550>
登入後複製

在這裡,我們使用類別屬性存取函數,正如預期的那樣列印do_stuff 是MyClass 的函數。然而,我們也可以使用實例屬性來存取它:

print(instance.do_stuff)
# <bound method MyClass.do_stuff of <__main__.MyClass object at 0x7ff80c78de50>
登入後複製

但在這種情況下,我們得到的是一個「綁定方法」而不是原始函數。 Python 在這裡為我們所做的是,它將類別屬性綁定到實例,創建了所謂的「綁定方法」。這個「綁定方法」是底層函數的包裝,該函數已經將實例插入為第一個參數(self)。

因此,方法是普通函數,它們的其他參數前附加了類別實例(self)。

要了解這是如何發生的,我們需要看一下描述符協定。

描述子協定

描述子是方法背後的機制,它們是定義 __get__()、__set__() 或 __delete__() 方法的物件(類別)。為了理解 self 是如何運作的,我們只考慮 __get__(),它有一個簽名:

descr.__get__(self, instance, type=None) -> value
登入後複製

但是 __get__() 方法實際上做了什麼?它允許我們自訂類別中的屬性查找 - 或者換句話說 - 自訂使用點符號存取類別屬性時發生的情況。考慮到方法實際上只是類別的屬性,這非常有用。這意味著我們可以使用 __get__ 方法來建立一個類別的「綁定方法」。

為了讓它更容易理解,讓我們透過使用描述符實作一個「方法」來示範這一點。首先,我們建立一個函數物件的純 Python 實作:

import types
class Function:
def __get__(self, instance, objtype=None):
if instance is None:
return self
return types.MethodType(self, instance)
def __call__(self):
return
登入後複製

上面的 Function 類別實作了 __get__ ,這使它成為一個描述符。這個特殊方法在實例參數中接收類別實例 - 如果這個參數是 None,我們知道 __get__ 方法是直接從一個類別(例如 MyClass.do_stuff)呼叫的,所以我們只回傳 self。但是,如果它是從類別實例中呼叫的,例如 instance.do_stuff,那麼我們傳回 types.MethodType,這是一種手動建立「綁定方法」的方式。

此外,我們也提供了 __call__ 特殊方法。 __init__ 是在呼叫類別來初始化實例時呼叫的(例如 instance = MyClass()),而 __call__ 是在呼叫實例時呼叫的(例如 instance())。我們需要用這個,是因為 types.MethodType(self, instance) 中的 self 必須是可呼叫的。

現在我們有了自己的函數實現,我們可以使用它將方法綁定到類別:

class MyClass:
do_stuff = Function()
print(MyClass.__dict__["do_stuff"])# __get__ not invoked
# <__main__.Function object at 0x7f229b046e50>
print(MyClass.do_stuff)# __get__ invoked, but "instance" is None, "self" is returned
print(MyClass.do_stuff.__get__(None, MyClass))
# <__main__.Function object at 0x7f229b046e50>
instance = MyClass()
print(instance.do_stuff)#__get__ invoked and "instance" is not None, "MethodType" is returned
print(instance.do_stuff.__get__(instance, MyClass))
# <bound method ? of <__main__.MyClass object at 0x7fd526a33d30>
登入後複製

透過給MyClass 一個Function 類型的屬性do_stuff,我們大致模擬了Python 在類別的命名空間中定義方法時所做的事情。

綜上所述,在instance.do_stuff等屬性存取時,do_stuff在instance的屬性字典(__dict__)中尋找。如果do_stuff 定義了__get__ 方法,則調用do_stuff.__get__ ,最終調用:

# For class invocation:
print(MyClass.__dict__['do_stuff'].__get__(None, MyClass))
# <__main__.Function object at 0x7f229b046e50>
# For instance invocation:
print(MyClass.__dict__['do_stuff'].__get__(instance, MyClass))
# Alternatively:
print(type(instance).__dict__['do_stuff'].__get__(instance, type(instance)))
# <bound method ? of <__main__.MyClass object at 0x7fd526a33d30>
登入後複製

正如我們現在所知- 將返回一個綁定方法- 一個圍繞原始函數的可調用包裝器,它的參數前面有self !

如果想進一步探索這一點,可以類似地實作靜態和類別方法(https://docs.python.org/3.7/howto/descriptor.html#static-methods-and-class-methods)

為什麼self在方法定義中?

我們現在知道它是如何運作的,但還有一個更哲學的問題——「為什麼它必須出現在方法定義中?」

明確self 方法參數是有爭議的設計選擇,但它是一種有利於簡單性的選擇。

Python 的自我體現了「越差越好」的設計理念——在此處進行了描述。這種設計理念的優先順序是“簡單”,定義為:

設計必須簡單,包括實作和介面。實現比介面簡單更重要...

這正是 self 的情況——一個簡單的實現,以介面為代價,其中方法簽名與其呼叫不匹配。

當然還有更多的原因為什麼我們要明確的寫self,或者說為什麼它必須保留, Guido van Rossum 在博客文章中描述了其中一些(http://neopythonic.blogspot.com/ 2008/10/why-explicit-self-has-to-stay.html),文章回覆了要求刪除的提議。

Python 抽象化了許多複雜性,但在我看來,深入研究低階細節和複雜性對於更好地理解語言的工作原理非常有價值,當事情發生故障和高級故障排除/調試時,它可以派上用場不夠。

此外,理解描述符實際上可能非常實用,因為它們有一些用例。雖然大多數時候你真的只需要@property 描述符,但在某些情況下自訂的描述符是有意義的,例如 SLQAlchemy 中的或者 e.g.自訂驗證器。

以上是Python中的self參數是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

在PHP和Python之間進行選擇:指南 在PHP和Python之間進行選擇:指南 Apr 18, 2025 am 12:24 AM

PHP適合網頁開發和快速原型開發,Python適用於數據科學和機器學習。 1.PHP用於動態網頁開發,語法簡單,適合快速開發。 2.Python語法簡潔,適用於多領域,庫生態系統強大。

PHP和Python:深入了解他們的歷史 PHP和Python:深入了解他們的歷史 Apr 18, 2025 am 12:25 AM

PHP起源於1994年,由RasmusLerdorf開發,最初用於跟踪網站訪問者,逐漸演變為服務器端腳本語言,廣泛應用於網頁開發。 Python由GuidovanRossum於1980年代末開發,1991年首次發布,強調代碼可讀性和簡潔性,適用於科學計算、數據分析等領域。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

sublime怎麼運行代碼python sublime怎麼運行代碼python Apr 16, 2025 am 08:48 AM

在 Sublime Text 中運行 Python 代碼,需先安裝 Python 插件,再創建 .py 文件並編寫代碼,最後按 Ctrl B 運行代碼,輸出會在控制台中顯示。

vs code 可以在 Windows 8 中運行嗎 vs code 可以在 Windows 8 中運行嗎 Apr 15, 2025 pm 07:24 PM

VS Code可以在Windows 8上運行,但體驗可能不佳。首先確保系統已更新到最新補丁,然後下載與系統架構匹配的VS Code安裝包,按照提示安裝。安裝後,注意某些擴展程序可能與Windows 8不兼容,需要尋找替代擴展或在虛擬機中使用更新的Windows系統。安裝必要的擴展,檢查是否正常工作。儘管VS Code在Windows 8上可行,但建議升級到更新的Windows系統以獲得更好的開發體驗和安全保障。

vscode在哪寫代碼 vscode在哪寫代碼 Apr 15, 2025 pm 09:54 PM

在 Visual Studio Code(VSCode)中編寫代碼簡單易行,只需安裝 VSCode、創建項目、選擇語言、創建文件、編寫代碼、保存並運行即可。 VSCode 的優點包括跨平台、免費開源、強大功能、擴展豐富,以及輕量快速。

visual studio code 可以用於 python 嗎 visual studio code 可以用於 python 嗎 Apr 15, 2025 pm 08:18 PM

VS Code 可用於編寫 Python,並提供許多功能,使其成為開發 Python 應用程序的理想工具。它允許用戶:安裝 Python 擴展,以獲得代碼補全、語法高亮和調試等功能。使用調試器逐步跟踪代碼,查找和修復錯誤。集成 Git,進行版本控制。使用代碼格式化工具,保持代碼一致性。使用 Linting 工具,提前發現潛在問題。

See all articles