搜尋
首頁後端開發Python教學Python中的self參數是什麼?

Python中的self參數是什麼?

May 08, 2023 pm 05:49 PM
pythonelf

Python 的

讓我們從我們已經知道的開始: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中文網其他相關文章!

陳述
本文轉載於:51CTO.COM。如有侵權,請聯絡admin@php.cn刪除
在Python陣列上可以執行哪些常見操作?在Python陣列上可以執行哪些常見操作?Apr 26, 2025 am 12:22 AM

Pythonarrayssupportvariousoperations:1)Slicingextractssubsets,2)Appending/Extendingaddselements,3)Insertingplaceselementsatspecificpositions,4)Removingdeleteselements,5)Sorting/Reversingchangesorder,and6)Listcomprehensionscreatenewlistsbasedonexistin

在哪些類型的應用程序中,Numpy數組常用?在哪些類型的應用程序中,Numpy數組常用?Apr 26, 2025 am 12:13 AM

NumPyarraysareessentialforapplicationsrequiringefficientnumericalcomputationsanddatamanipulation.Theyarecrucialindatascience,machinelearning,physics,engineering,andfinanceduetotheirabilitytohandlelarge-scaledataefficiently.Forexample,infinancialanaly

您什麼時候選擇在Python中的列表上使用數組?您什麼時候選擇在Python中的列表上使用數組?Apr 26, 2025 am 12:12 AM

useanArray.ArarayoveralistinpythonwhendeAlingwithHomoGeneData,performance-Caliticalcode,orinterfacingwithccode.1)同質性data:arraysSaveMemorywithTypedElements.2)績效code-performance-calitialcode-calliginal-clitical-clitical-calligation-Critical-Code:Arraysofferferbetterperbetterperperformanceformanceformancefornallancefornalumericalical.3)

所有列表操作是否由數組支持,反之亦然?為什麼或為什麼不呢?所有列表操作是否由數組支持,反之亦然?為什麼或為什麼不呢?Apr 26, 2025 am 12:05 AM

不,notalllistoperationsareSupportedByArrays,andviceversa.1)arraysdonotsupportdynamicoperationslikeappendorinsertwithoutresizing,wheremactsperformance.2)listssdonotguaranteeconecontanttanttanttanttanttanttanttanttanttimecomplecomecomplecomecomecomecomecomecomplecomectacccesslectaccesslecrectaccesslerikearraysodo。

您如何在python列表中訪問元素?您如何在python列表中訪問元素?Apr 26, 2025 am 12:03 AM

toAccesselementsInapythonlist,useIndIndexing,負索引,切片,口頭化。 1)indexingStartSat0.2)否定indexingAccessesessessessesfomtheend.3)slicingextractsportions.4)iterationerationUsistorationUsisturessoreTionsforloopsoreNumeratorseforeporloopsorenumerate.alwaysCheckListListListListlentePtotoVoidToavoIndexIndexIndexIndexIndexIndExerror。

Python的科學計算中如何使用陣列?Python的科學計算中如何使用陣列?Apr 25, 2025 am 12:28 AM

Arraysinpython,尤其是Vianumpy,ArecrucialInsCientificComputingfortheireftheireffertheireffertheirefferthe.1)Heasuedfornumerericalicerationalation,dataAnalysis和Machinelearning.2)Numpy'Simpy'Simpy'simplementIncressionSressirestrionsfasteroperoperoperationspasterationspasterationspasterationspasterationspasterationsthanpythonlists.3)inthanypythonlists.3)andAreseNableAblequick

您如何處理同一系統上的不同Python版本?您如何處理同一系統上的不同Python版本?Apr 25, 2025 am 12:24 AM

你可以通過使用pyenv、venv和Anaconda來管理不同的Python版本。 1)使用pyenv管理多個Python版本:安裝pyenv,設置全局和本地版本。 2)使用venv創建虛擬環境以隔離項目依賴。 3)使用Anaconda管理數據科學項目中的Python版本。 4)保留系統Python用於系統級任務。通過這些工具和策略,你可以有效地管理不同版本的Python,確保項目順利運行。

與標準Python陣列相比,使用Numpy數組的一些優點是什麼?與標準Python陣列相比,使用Numpy數組的一些優點是什麼?Apr 25, 2025 am 12:21 AM

numpyarrayshaveseveraladagesoverandastardandpythonarrays:1)基於基於duetoc的iMplation,2)2)他們的aremoremoremorymorymoremorymoremorymoremorymoremoremory,尤其是WithlargedAtasets和3)效率化,效率化,矢量化函數函數函數函數構成和穩定性構成和穩定性的操作,製造

See all articles

熱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

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

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具