您好,登錄后才能下訂單哦!
這篇文章給大家介紹Python中self的四個秘密分別是什么,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
毫無疑問,幾乎每一門Python課程都有一個關于(class)類的講座——面向對象編程語言的基本構建模塊之一。
當您通過一些示例學習它時,您將注意到在Python類中定義的許多函數都將self作為它們的第一個參數。例如,在下面的代碼片段中,我們聲明了一個名為Student的類,它的greet()方法的第一個參數是self。但是,函數根本沒有使用self,所以這里的self到底是從哪里來的呢?這對許多初學者來說是第一個謎。
>>> class Student: ... def greet(self, name): ... print('Good Morning, ' + name) ... >>> student = Student() >>> student.greet('John') Good Morning, John
同樣奇怪的是,當我們使用這個函數時,我們并沒有給self參數設置任何東西,這是困擾我們的另一個謎題。在這篇文章中,我們將與學習者分享一些Python中self的奧秘。
在開始處理這個謎題之前,我們需要理解兩個基本的相關概念:類和實例。當然,解決所有這些謎題需要額外的知識,而不僅僅是類和實例,我將在接下來的討論中澄清這一點。如果你對這兩個概念都很了解,你可以跳過下一段,這段只是對這兩個概念的簡要概述。
創建Python類就是聲明一種新的對象類型,它提供了一種將數據和功能捆綁在一起的機制。在上面的示例中,我們創建了一個名為Student的類,并使用它創建了一個名為Student的學生類型的對象。這個對象被稱為student類的實例。此外,類還可以提供通常稱為屬性的特定功能,例如示例中的greet()函數。我們使用三個內省(introspection)函數(type()、isinstance()和hasattr())來檢查相關信息。
>>> type(Student) <class 'type'> >>> type(student) <class '__main__.Student'> >>> isinstance(student, Student) True >>> hasattr(Student, 'greet') True
我可以簡單地告訴您,greet()函數中的self參數是上面示例中的student實例。更一般地說,是實例調用這個函數。以下是支持證據:
>>> class Student: ... def greet(self, name): ... print(id(self)) ... print('Good Morning, ' + name) ... >>> student = Student() >>> student.greet('John') 4546580944 Good Morning, John >>> id(student) 4546580944
在上面的代碼中,我們修改了greet()函數,要求它使用內省id()函數向我們顯示self參數的內存地址。如您所見,self參數和實例student是同一個對象,因為它們具有相同的內存地址。
繼續上一節中展示的示例,當我們使用實例student調用greet()函數時,這個函數通常被稱為實例方法——一個對某個類的實例可用的函數。但是,如果我們檢查這個屬性的類型,就會顯示一些不同的東西。
>>> student = Student() >>> student.greet <bound method Student.greet of <__main__.Student object at 0x10eff5750>>
如上所述,實例student的greet屬性稱為綁定方法。具體來說,它被綁定到Student類的greet屬性。
為了準確理解這意味著什么,讓我們看看下面的代碼:
>>> Student.greet(student, 'John') Good Morning, John
結合開頭的示例,您可能會注意到這段代碼中的三件事:
這個函數的調用者是類Student,而不是實例student。
在這個調用中設置了self和name參數,這與student調用初始函數時忽略self參數不同。
兩個函數調用都產生了相同的輸出。它們本質上用的是同一個函數。
通過實現這些信息,您可能已經猜到在使用實例student調用greet()函數時,幕后發生了什么。
如上圖所示,當實例student調用greet(' John ')方法時,解釋器將處理此函數調用,作為類Student將調用者(即實例student)和name參數(即' John ')發送給greet(self, name)函數,該函數打印“Good Morning, John”。
對于感興趣的讀者,這里有幾件事要知道,可以幫助你更深入地了解這個謎。當創建一個Python類時,它聲明的函數就是這個類的屬性(稱為函數對象)。換句話說,類“擁有”這些函數。類的實例不會直接實現這些函數。相反,它們將具有與類中實現的相應函數綁定的相同屬性(即實例方法)。
似乎在所有這些已定義的函數中,我們都使用self作為它們的第一個參數。有些人可能錯誤地認為self是Python為這些用例保留的關鍵字。然而,事實并非如此。請看下面一個簡單的例子:
>>> def=5 File "<stdin>", line 1 def=5 ^ SyntaxError: invalid syntax >>> class=4 File "<stdin>", line 1 class=4 ^ SyntaxError: invalid syntax >>> self=3
你可能知道,def和class是Python中的關鍵字,我們不能用它們作為變量名。然而,我們可以在定義函數的上下文之外使用self作為變量名,這表明它在Python中不是保留關鍵字。
在上面的例子中,我們重復引用了greet()函數。正如我們已經討論過的,我們將這個函數實現為一個實例方法,這樣它就可以被這個Student類的所有實例使用。在這種情況下,self是必需的。下面是一些證據:
>>> class Teacher: ... def say_hello(name): ... print('Hello, ' + name) ... >>> teacher = Teacher() >>> teacher.say_hello('John') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: say_hello() takes 1 positional argument but 2 were given
這里有一些分析。如前所述,當實例teacher調用say_hello()方法時,發生的事情是執行teacher .say_hello()函數,并將實例對象teacher和' John '設置為函數調用。這就是為什么錯誤說“2是給定的。這與函數的定義相反,函數的定義只有一個參數(name)。
然而,還有兩件事與這個謎有關,你可能想知道:
雖然聲明實例方法需要包含self參數,但它不必命名為self。在這個場景中使用這個名稱只是每個Python程序員都能欣賞的一種約定。下面是一個例子,它可以被命名為其他東西而不會引起任何問題。盡管它在語法上是正確的,但不推薦使用,因為它只會讓其他Python程序員感到困惑:
>>> class Teacher: ... def say_hello(professor, name): ... print('Hello, ' + name) ... >>> teacher = Teacher() >>> teacher.say_hello('John') Hello, John
在聲明其他函數(如類和靜態方法)時,不需要使用self參數。對類和靜態方法的清晰解釋將是以后文章的主題。但我在這里可以展示的是,當我們聲明一個類方法時,函數確實有一些類似于在實例方法中使用self的東西,它通常被稱為cls,引用類對象本身。它與具體實例無關。下面是一個例子:
>>> class Student: ... def __init__(self, name): ... self.name = name ... @classmethod ... def with_names(cls, first_name, last_name): ... return cls(first_name + ' ' + last_name) ... >>> student = Student.with_names('John', 'Smith') >>> student.name 'John Smith'
關于Python中self的四個秘密分別是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。