Python物件導向-擴充

來源:互聯網
上載者:User

標籤:技術分享   父類   __weak   語句   line   廣度   import   metaclass   lte   

擷取對象資訊

拿到一個變數,除了用 isinstance() 判斷它是否是某種類型的執行個體外,還有沒有別的方法擷取到更多的資訊呢?

例如,已有定義:

class Person(object):    def __init__(self, name, gender):        self.name = name        self.gender = genderclass Student(Person):    def __init__(self, name, gender, score):        super(Student, self).__init__(name, gender)        self.score = score    def whoAmI(self):        return 'I am a Student, my name is %s' % self.name

首先可以用 type() 函數擷取變數的類型,它返回一個 Type 對象:

>>> type(123)<type 'int'>>>> s = Student('Bob', 'Male', 88)>>> type(s)<class '__main__.Student'>

其次,可以用 dir() 函數擷取變數的所有屬性:

>>> dir(123)   # 整數也有很多屬性...['__abs__', '__add__', '__and__', '__class__', '__cmp__', ...]>>> dir(s)['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gender', 'name', 'score', 'whoAmI']

對於執行個體變數,dir()返回所有執行個體屬性,包括__class__這類有特殊意義的屬性。注意到方法whoAmI也是 s 的一個屬性。

如何去掉__xxx__這類的特殊屬性,只保留我們自己定義的屬性?回顧一下filter()函數的用法。

dir()返回的屬性是字串列表,如果已知一個屬性名稱,要擷取或者設定對象的屬性,就需要用 getattr() 和 setattr( )函數了:

>>> getattr(s, 'name')  # 擷取name屬性'Bob'>>> setattr(s, 'name', 'Adam')  # 設定新的name屬性>>> s.name'Adam'>>> getattr(s, 'age')  # 擷取age屬性,但是屬性不存在,報錯:Traceback (most recent call last):  File "<stdin>", line 1, in <module>AttributeError: 'Student' object has no attribute 'age'>>> getattr(s, 'age', 20)  # 擷取age屬性,如果屬性不存在,就返回預設值20:20
新式類和舊式類

python的新式類是2.2版本引進來的,我們可以將之前的類叫做經典類或者舊類。

為什麼要在2.2中引進new style class呢?官方給的解釋是:為了統一類(class)和類型(type)

在2.2之前,比如2.1版本中,類和類型是不同的,

aClassA的一個執行個體,

那麼a.__class__返回class __main__.ClassA,type(a)返回總是<type ‘instance‘>

而引入新類後,比如ClassB是個新類,bClassB的執行個體,b.__class__type(b)都是返回‘class ‘__main__.ClassB‘,這樣就統一了。

引入新類後,還有其他的好處,比如更多的內建屬性將會引入,描述符的引入,屬性可以來計算等等。為了向前相容,預設情況下使用者定義的類為經典類,新類需要繼承自所有類的基類 object 或者繼承自object的新類。

? 值得注意的地方是,雖然使用的是最新的python(2.7),但是一些特性不會在舊式類起作用。

? 所以,為了確保自己使用的是新式類,有以下方法:

? 把這個指派陳述式放在類別模組代碼的最前面__metaclass__ = type(前面有提過)。

? 自己的類都從內建類object直接或者間接地繼承。

? 如果不需要相容舊式類,舊版本的類,那麼就保持都是新式類。

? 當然,在Python3裡面,不存在這些問題了,因為所有的類都是object類的子類(隱式)。

# encoding:utf-8# 新式類和舊式類的對比class OldStyle:    def __init__(self, name, description):        self.name = name        self.description = description#新類,可以在這裡加 __metaclass__ = type class NewStyle(object): #新類,也可以直接繼承至object類       def __init__(self, name, description):        self.name = name        self.description = descriptionif __name__ == '__main__':    old = OldStyle('old', 'Old style class')    print(old.__class__)    print((type(old)))    print((dir(old)))    print('-------------------------------------------------------')    new = NewStyle('new', 'New style class')    print(new.__class__)    print((type(new)))    print((dir(new)))

運行結果:

__main__.OldStyle<type 'instance'>['__doc__', '__init__', '__module__', 'description', 'name']-------------------------------------------------------<class '__main__.NewStyle'><class '__main__.NewStyle'>['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'description', 'name'][Finished in 0.1s]
多繼承屬性尋找機制

如果將每個類看成一個點,眾多的類就構成一張圖,那麼Python中繼承的機制是就是一種搜尋

那麼地,這種搜尋是深度優先搜尋,還是廣度優先搜尋呢?

上述的問題也叫做mromethod resolution order,主要用於在多繼承時判斷調的屬性的路徑(來自於哪個類)。

在舊式類(在Python2.3之前)之中類的多繼承機制是基於深度優先搜尋,但在新式類(從Python2.3起)之中類的多繼承機制是基於類似於廣度優先搜尋的C3演算法。

C3演算法

C3演算法最早被提出是用於Lisp的,應用在Python中是為瞭解決原來基於深度優先搜尋演算法不滿足本地優先順序,和單調性的問題。

  • 本地優先順序:指聲明時父類的順序,比如C(A,B),如果訪問C類對象屬性時,應該根據聲明順序,優先尋找A類,然後再尋找B類。
  • 單調性:如果在C的解析順序中,A排在B的前面,那麼在C的所有子類裡,也必須滿足這個順序。

在新式類中,尋找一個要調用的函數或者屬性的時候,是廣度優先搜尋的。

在舊式類當中,是深度優先搜尋的。如所示:

Python中幾種提供繼承順序的方法:

  • mro方法
  • __mro__屬性
  • inspect模組的getmro方法
import inspectclass A:    passclass B(A):    passprint(B.mro())print(B.__mro__)print(inspect.getmro(B))

運行結果:

[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>](<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

從上結果來看,以元組為結果的__mro__inspect.getmro看來更讓人滿意

深度優先廣度優先
  • 舊式類的深度優先搜尋的繼承機制
# -*- coding:utf-8 -*-from inspect import getmroclass D:    passclass B(D):    passclass C(D):    passclass A(B, C):    passif __name__ == '__main__':    print(getmro(A))

運行結果:

(<class __main__.A at 0x0000000002CEC888>, <class __main__.B at 0x0000000002CECE88>,<class __main__.D at 0x0000000002CEC8E8>, <class __main__.C at 0x0000000002CECD68>)[Finished in 0.1s]
  • 新式類的廣度優先搜尋的繼承機制
# -*- coding:utf-8 -*-from inspect import getmroclass D(object):    passclass B(D):    passclass C(D):    passclass A(B, C):    passif __name__ == '__main__':    print(getmro(A))

運行結果:

(<class '__main__.A'>, <class '__main__.B'>,  <class '__main__.C'>, <class '__main__.D'>,  <type 'object'>)[Finished in 0.1s]

Python物件導向-擴充

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.