亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python的對象模型是什么

發布時間:2023-05-06 14:47:47 來源:億速云 閱讀:97 作者:zzz 欄目:開發技術

本篇內容介紹了“Python的對象模型是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

在面向對象的理論中,有兩個核心的概念:類和實例。類可以看成是一個模板,實例就是根據這個模板創建出來的對象。但在 Python 里面,類和實例都是對象,也就是所謂的類對象(或者類型對象)和實例對象。

為了避免后續出現歧義,我們這里把對象分為三種:

  • 內置類對象:比如 int、str、list、type、object 等等;

  • 自定義類對象:通過 class 關鍵字定義的類,當然我們也會把它和上面的內置類對象統稱為類對象(或者類型對象);

  • 實例對象:由類對象(內置類對象或自定義類對象)創建的實例;

而對象之間存在以下兩種關系:

  • is-kind-of:對應面向對象理論中子類和父類之間的關系;

  • is-instance-of:對應面向對象理論中實例對象和類對象之間的關系;

我們舉例說明:

class Girl(object):

    def say(self):
        return "古明地覺"

girl = Girl()
print(girl.say())  # 古明地覺

這段代碼便包含了上面的三種對象:object(內置類對象),Girl(自定義類對象),girl(實例對象)。

顯然 Girl 和 object 之間是 is-kind-of 關系,即 Girl 是 object 的子類。值得一提的是,Python3 里面所有的類(除 object)都是默認繼承自 object,即便我們這里不顯式繼承 object,也會默認繼承的,但為了說明,我們就寫上了。

除了 Girl 是 object 的子類,我們還能看出 girl 和 Girl 之間存在 is-instance-of 關系,即 girl 是 Girl 的實例。當然如果再進一步的話,girl 和 object 之間也存在 is-instance-of 關系,girl 也是 object 的實例。

class Girl(object):
    pass
    
girl = Girl()
print(issubclass(Girl, object))  # True 
print(type(girl))  # <class '__main__.Girl'>
print(isinstance(girl, Girl))  # True
print(isinstance(girl, object))  # True

girl 是 Girl 這個類實例化得到的,所以 type(girl) 得到的是類對象 Girl。但 girl 也是 object 的實例對象,因為 Girl 繼承了 object。至于這其中的原理,我們會慢慢介紹。

Python 也提供了一些手段可以探測這些關系,除了上面的 type 之外,還可以使用對象的 __class__ 屬性探測一個對象和其它的哪些對象之間存在 is-instance-of 關系。

而通過對象的 __bases__ 屬性則可以探測一個對象和其它的哪些對象之間存在著 is-kind-of 關系。此外 Python 還提供了兩個函數 issubclass 和 isinstance 來驗證兩個對象之間是否存在著我們期望的關系。

class Girl(object):
    pass 

girl = Girl()
print(girl.__class__)  # <class '__main__.Girl'>
print(Girl.__class__)  # <class 'type'>
# __class__是查看自己的類型是什么,也就是生成自己的類
# 而在介紹 Python 對象的時候,我們就看到了
# 任何一個對象都至少具備兩個東西: 一個是引用計數、一個是類型
# 所以 __class__ 是所有對象都具備的

# __base__只顯示直接繼承的第一個類
print(Girl.__base__)  # <class 'object'>
# __bases__ 會顯示直接繼承的所有類,以元組的形式
print(Girl.__bases__)  # (<class 'object'>,)

我們畫一張圖總結一下:

Python的對象模型是什么

另外需要注意里面的 type 和 object:

  • type 和 object 存在 is-kind-of 關系,因為 type 是 object 的子類;

  • object 和 type 存在 is-instance-of 關系,因為 object 是 type 的實例對象;

可能有人會好奇為什么會是這樣,而關于這一點,我在 type 與 object 的恩怨糾葛這篇文章講得很詳細了,感興趣可以點擊閱讀一下。

簡單來說就是,type 在底層對應的結構體為 PyType_Type、object 在底層對應的結構體為 PyBaseObject_Type。而在創建 object 的時候,將內部的 ob_type 設置成了&PyType_Type;在創建type的時候,將內部的 tp_base 設置成了&PyBaseObject_Type。

因此這兩者的定義是彼此依賴的,兩者是同時出現的,我們后面還會看到。

另外 type 的類型就是 type 本身,所以:

  • 實例對象的類型是類型對象,類型對象的類型是元類;

  • 所有類型對象的基類都收斂于 object;

  • 所有對象的類型都收斂于 type;

Python的對象模型是什么

因此 Python 算是將一切皆對象的理念貫徹到了極致,也正因為如此,Python 才具有如此優秀的動態特性。

但還沒有結束,我們看一下類對象 Girl 的行為,首先它支持屬性設置:

class Girl(object):
    pass

print(hasattr(Girl, "name"))  # False
Girl.name = "古明地覺"
print(hasattr(Girl, "name"))  # True
print(Girl.name)  # 古明地覺

一個類都已經定義完了,我們后續還可以進行屬性添加,這在其它的靜態語言中是不可能做到的。那么Python是如何做到的呢?我們說能夠對屬性進行動態添加,你會想到什么?是不是字典呢?

正如 global 名字空間一樣,我們猜測類應該也有自己的屬性字典,往類里面設置屬性的時候,等價于向字典中添加鍵值對,同理其它操作也與之類似。

class Girl(object):
    pass

print(Girl.__dict__.get("name", "不存在"))  # 不存在
Girl.name = "古明地覺"
print(Girl.__dict__.get("name"))  # 古明地覺

和操作全局變量是類似的,但是有一點需要注意:我們不能直接通過類的屬性字典來設置屬性。

try:
    Girl.__dict__["name"] = "古明地覺"
except Exception as e:
    print(e)  
# 'mappingproxy' object does not support item assignment

雖然叫屬性字典,但其實是 mappingproxy 對象,該對象本質上就是對字典進行了一層封裝,在字典的基礎上移除了增刪改操作,也就是只保留了查詢功能。如果我們想給類增加屬性,可以采用直接賦值的方式,或者調用 setattr 函數也是可以的。

但在介紹如何篡改虛擬機的時候,我們提到過一個騷操作,可以通過 gc 模塊拿到 mappingproxy 對象里的字典。

import gc

class Girl(object):
    pass

gc.get_referents(Girl.__dict__)[0]["name"] = "古明地覺"
print(Girl.name)  # 古明地覺

并且這種做法除了適用于自定義類對象,還適用于內置類對象。但是工作中不要這么做,知道有這么個操作就行。

除了設置屬性之外,我們還可以設置函數。

class Girl(object):
    pass

Girl.info = lambda name: f"我是{name}"
print(Girl.info("古明地覺"))  # 我是古明地覺

# 如果實例調用的話,會和我們想象的不太一樣
# 因為實例調用的話會將函數包裝成方法
try:
    Girl().info("古明地覺")
except TypeError as e:
    print(e) 
"""
<lambda>() takes 1 positional argument but 2 were given
"""    

# 實例在調用的時候會將自身也作為參數傳進去
# 所以第一個參數 name 實際上接收的是 Girl 的實例對象
# 只不過第一個參數按照規范來講應該叫做self
# 但即便你起別的名字也是無所謂的
print(Girl().info())  
"""
我是<__main__.Girl object at 0x000001920BB88760>
"""

所以我們可以有兩種做法:

# 將其包裝成一個靜態方法
# 這樣類和實例都可以調用
Girl.info = staticmethod(lambda name: f"我是{name}")
print(Girl.info("古明地覺"))  # 我是古明地覺
print(Girl().info("古明地覺"))  # 我是古明地覺

# 如果是給實例用的,那么帶上一個 self 參數即可
Girl.info = lambda self, name: f"我是{name}"
print(Girl().info("古明地覺"))  # 我是古明地覺

此外我們還可以通過 type 來動態地往類里面進行屬性的增加、修改和刪除。

class Girl(object):

    def say(self):
        pass

print(hasattr(Girl, "say"))  # True
# delattr(Girl, "say") 與之等價
type.__delattr__(Girl, "say")
print(hasattr(Girl, "say"))  # False
# 我們設置一個屬性吧
# 等價于 Girl.name = "古明地覺"
setattr(Girl, "name", "古明地覺")
print(Girl.name)  # 古明地覺

事實上調用 getattr、setattr、delattr 等價于調用其類型對象的__getattr__、__setattr__、__delattr__。

所以,一個對象支持哪些行為,取決于其類型對象定義了哪些操作。并且通過對象的類型對象,可以動態地給該對象進行屬性的設置。Python 所有類型對象的類型對象都是 type,通過 type 我們便可以控制類的生成過程,即便類已經創建完畢了,也依舊可以進行屬性設置。

但是注意:type 可以操作的類只能是通過 class 定義的動態類,而像 int、list、dict 等靜態類,它們是在源碼中靜態定義好的,只不過類型設置成了 type。一言以蔽之,type 雖然是所有類對象的類對象,但 type 只能對動態類進行屬性上的修改,不能修改靜態類。

try:
    int.name = "古明地覺"
except Exception as e:
    print(e)
"""
can't set attributes of built-in/extension type 'int'
"""

try:
    setattr(int, "ping", "pong")
except Exception as e:
    print(e)
"""
can't set attributes of built-in/extension type 'int'     
"""

通過報錯信息可以看到,不可以設置內置類和擴展類的屬性,因為內置類在解釋器啟動之后,就已經初始化好了。至于擴展類就是我們使用 Python/C API 編寫的擴展模塊中的類,它和內置類是等價的。

因此內置類和使用 class 定義的類本質上是一樣的,都是 PyTypeObject 對象,它們的類型在 Python 里面都是 type。但區別在于內置類在底層是靜態初始化的,我們不能進行屬性的動態設置(通過 gc 模塊實現除外)。

但是為什么不可以對內置類和擴展類進行屬性設置呢?首先我們要知道 Python 的動態特性是虛擬機賜予的,而虛擬機的工作就是將 PyCodeObject 對象翻譯成 C 的代碼進行執行,所以 Python 的動態特性就是在這一步發生的。

而內置類在解釋器啟動之后就已經靜態初始化好了,直接指向 C 一級的數據結構,同理擴展類也是如此。它們相當于繞過了解釋執行這一步,所以它們的屬性不可以動態添加。

不光內置的類本身,還有它的實例對象也是如此。

a = 123
print(hasattr(a, "__dict__"))  # False

我們看到它連自己的屬性字典都沒有,因為內置類對象的實例對象,內部有哪些屬性,解釋器記得清清楚楚。它們在底層都已經寫死了,并且不允許修改,因此虛擬機完全沒有必要為其實現屬性字典(節省了內存占用)。

“Python的對象模型是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

博白县| 平安县| 广宗县| 普格县| 六枝特区| 泽普县| 普兰店市| 寿光市| 泰安市| 乌拉特后旗| 威远县| 启东市| 江达县| 巨鹿县| 西峡县| 且末县| 金乡县| 张家川| 阿勒泰市| 宜丰县| 旺苍县| 同心县| 商水县| 鹤山市| 庆城县| 大兴区| 体育| 蒲城县| 两当县| 民丰县| 丰宁| 安塞县| 夏邑县| 苏尼特右旗| 繁昌县| 凌海市| 湘西| 广水市| 西藏| 荣成市| 察隅县|