Python對象的方法調用時發生了什么?
一、Python對象的方法調用時發生了什么
1.尋找Eat
catObj尋找一個叫Eat的東西,這東西可能是任意對象,名字就叫Eat(暫且先忘了Cat類里定義了什么),這其實就涉及到Python屬性訪問順序了:
__getattribute__數據描述符對象屬性類屬性非數據描述符父類屬性__getattr__()為了更簡單得去理解,本文只關注對象屬性,類屬性,父類屬性這三點。
首先從對象屬性去找:
catObj對象有沒有名為Eat這個屬性?從上面定義的Cat類看顯然是沒有,這個對象只有一個屬性name,可打印__dict__查看對象的屬性。
print(catObj.__dict__)
# 打印結果:
# {‘name’: ‘Godeng’}
catObj.food = “Fish”
# 打印結果:
# {‘name’: ‘Godeng’, ‘food’: ‘Fish’}
對象添加一個屬性,它就會進對象的__dict__里,歸根結底都是字典訪問。
對象屬性找不到,去類屬性找,從catObj對象的__class__屬性即可索引到類:
Cat類有沒有名為Eat這個屬性?從上面定義的Cat類看,顯然是有的,且類也是對象,也可通過打印__dict__觀察它的屬性。
print(Cat.__dict__)
# 打印結果:
# {…’Eat’:
# ‘__init__’:
Eat和__init__赫然在列,而且Eat和__init__是一個質樸得不能再質樸的函數,函數,函數。
如果在類屬性找不到的話,就會嘗試去父類屬性尋找,相似的過程。
那么到此,尋找到了一個名為Eat的函數。
2.包裝成Eat方法&調用
def Eat(self):
??? print(“Cat is eating”)
從catObj對象一路尋找到的Eat函數是長這樣的,但它并非最終的返回的方法。將函數與對象進行包裝后的產物,才是方法。
class Method(object):
??? def __init__(self, obj, func):
?????? self.__self__ = obj
?????? self.__func__ = func
??? def __call__(self, *args, **kwargs):
?????? self.__func__(self.__self__, *args, **kwargs)
catObj = Cat(“Godeng”)
eatMethod = Method(catObj, Cat.Eat)
eatMethod()
上面是模擬方法的結構和大致產生調用過程,方法對象自身會引用Cat類函數Eat,和eatObj對象,并方法對象被調用時(__call__調用時),自動把eatObj對象作為了該函數的self參數。
并非方法本身蘊含了什么不可告人的魔力,catObj.eat獲取的其實就是類似上例的Method對象,從使用形式來看它提供的一個顯著特點是,他就像一個不需要傳self參數的函數。
方法&類函數引用上的區別:
類函數Cat.Eat是一個普通函數對象,它被Cat類引用。
catObj.Eat是一個方法對象,它引用了類函數Cat.Eat和catObj對象,它并不是像類函數那樣有被Cat類或catObj對象引用的一個恒久的對象,每次catObj.Eat的調用都會走一遍上述流程,產生一個新的方法對象返回。
# 生成了一個新的方法對象,這句執行完畢后方法對象會被銷毀
catObj.Eat()
# 生成了一個新的方法對象, 并由eatMethod引用,方法對象不會被銷毀
eatMethod = catObj.Eat
# 刪除eatMethod的引用,方法對象隨之被銷毀
eatMethod = None
延伸閱讀:
二、如何從父類們找類函數
Python是門多繼承語言,在上面catObj尋找Eat到它的類的時候,如果Cat類沒有定義Eat,會嘗試向父類尋找Eat。
class Monster(object):
??? def Eat(self):
?????? print(“Monster Eat”)
class Pet(object):
??? def Eat(self):
?????? print(“Pet Eat”)
class Cat(Pet, Monster):
??? def __init__(self, name):
?????? self.name = name
假如Cat沒定義Eat,它的兩個父類Pet和Monster的都定義了Eat,那就是先在哪個父類找到Eat,那么就返回哪個父類的Eat,也即是取決于先從Pet類找,還是先從Monster類找。
這就涉及到Python一個老生常談的概念,方法解析順序(mro),它確定了這個順序,它的具體規則會隨著Python版本迭代而迭代,如Py2是深度優先和Py3是廣度優先,具體在此就不展開了。
可通過打印類的mro來觀察類的執行順序。
print(Cat.mro())
print(Cat.Eat)
# 打印結果:
# [
#

猜你喜歡LIKE
相關推薦HOT
更多>>
mysql怎么查看連接池是否已滿?
一、mysql怎么查看連接池是否已滿1.查看連接數配置(MySQL服務器允許的最大連接數16384)show variables like ‘%max_connections%’2.查看當前...詳情>>
2023-10-17 21:20:19
什么是職場情商,如何提高?
什么是情商?情商是一個 20 世紀 90 年代作為學術話題出現的概念,并迅速成為商業心理學和職場動態研究的重要組成部分。它通常被稱為 EQ(情商...詳情>>
2023-10-17 20:16:30
vector, list, map等容器使用場合是什么?
一、vector, list, map等容器使用場合vector適用于對象簡單,變化較小,并且頻繁隨機訪問的場景。list適用經常進行插入和刪除并且不經常隨機訪...詳情>>
2023-10-17 19:45:03
數據挖掘中涉及的關聯規則在實際生活中的應用有哪些?
一、數據挖掘中涉及的關聯規則在實際生活中的應用關于關聯規則分析,這篇文章可以認真學習一下,講的比較全面,關聯規則分析還在零售、快消、電...詳情>>
2023-10-17 18:40:06熱門推薦
sql server2012r2所在服務器做端口限制,需要開放什么端口才能繼續訪問數據庫?
沸Oracle有什么優勢和劣勢?
熱數據庫聚集索引非聚集索引實現上有哪些區別?
熱數據庫(如oracle、mysql)及編程語言(php、python、perl、lisp)的區別?
新CSS 隱藏頁面元素有哪些方法?
除了cx_Oracle,python還可以通過什么方式訪問Oracle數據庫?
SQL開啟事務處理的語句 START TRANSACTION 和BEGIN TRAN的區別?
Android適配你需要學習哪些?
開發web應用,好的開發流程是怎么樣的?
為什么說Gradle是Android進階繞不去的坎?
mysql怎么查看連接池是否已滿?
WHERE中有很多IN判斷怎么提速?
軟件開發要遵循哪些事項?
有了innodb buffer pool為什么要有redis?
技術干貨






