Python類型和對象


關鍵字:Python 類型 對象
原文:http://wiki.woodpecker.org.cn/moin/PyTypesAndObjects

關於本書

解釋新式的Python對象(new-style):

  • <type 'type'> and <type 'object'>是什么東西

  • 用戶定義的類及實例是如何相互關聯的,和內置類型有啥關系how user defined classes and instances are related to each other and to built-in types
  • metaclass是什么

新式類型New-style包含在Python2.2及以上,包括3.x。這些版本之間會有細微差異,不過這里涉及到的概念都是無差別的。本書講的內容通常被稱作Python類型系統或Python對象模型Python type system, or the object model.

This revision: 1.24

 

圖索引

 

示例索引

 

需要提前了解的

應該注意的一些:

  • 本書涵蓋新式 new-style 對象 (在Python 2.2中引入). 本書例子適用於Python 2.5 及以上,包括 Python 3.x.
  • 本書不是為完全初學者寫的. 而是針對已經對Python有所了解 (稍稍了解即可) 並希望對它了解更多的人.
  • 本書為掌握新式(new-style)屬性訪問及descriptors, properties等機制提供了所需的底層的要點。如果只對屬性方法感興趣,請移步至 Python Attributes and Methods, 閱讀之后也就理解了本書的 Summary.

python之旅快樂?Happy pythoneering!

 

1. 基本概念

 

深入Object

怎樣准確的表達python中object的含義呢? 系統中每個對象是一條規則 - 是一個實體的體現. 可以通過如下特征來確定一個對象:

  • 有標識名字 (i.e. 給定兩個名字我們可以判斷他們是否指向同一個對象).
  • 有值 - 對象可能包含一堆屬性 (i.e. 比如可以通過 objectname.attributename獲得其他對象).
  • 有類型 type - 每個對象有一個確定的類型. 例如對象2的類型是 int ,對象 "joe" 的類型是 string.
  • 有一個或多個 bases. 並非所有對象都有bases,一些特別的對象會有. A base 類似於面向對象術語中的超類或基類。
  • 如果你更在意具體的對象在內存中怎樣存放,而不是更想知道一些抽象的概念,
  • 這對你理解每個對象在內存中都有個具體的位置(可以用id函數來獲得)很有幫助。(---注:這句瞎解得,沒真正理解,附原文)
  • If you are more of the 'I like to know how the bits are laid out' type as opposed to the 'I like the meta abstract ideas' type, it might be useful for you to know that each object also has a specific location in main memory that you can find by calling the id() function.

==== type 和 bases === (如果存在的話) 很重要,因為它們定義了對象和其他對象之間的特定關系. 請記住對象的types 和 bases只是另外一些對象.很快就會看到這一點.

你可能會想到對象有名字但名字不是對象的一部分. 對象名在對象之外的命名空間中存在(比如函數的本地變量) 或者作為另一個對象的屬性.

即使對2這樣一個簡單對象所包含的東西也比我們眼睛看到的要多.

Example1.1. 查看integer對象

>>> two = 2   1
>>> type(two)
<type 'int'> 2
>>> type(type(two))
<type 'type'> 3
>>> type(two).__bases__
(<type 'object'>,) 4
>>> dir(two) 5
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', 
 '__delattr__', '__div__', '__divmod__', '__doc__', '__float__',
 '__floordiv__', '__format__', '__getattribute__', '__getnewargs__',
 '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__',
 '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__',
 '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__',
 '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__',
 '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__',
 '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
 '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__',
 '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__',
 'conjugate', 'denominator', 'imag', 'numerator', 'real']

 

  • 1 在當前命名空間中我們把這個integer命名為two.
  • 2 <type 'int'>. 這是另一個對象, 現在來解剖一下. 注意這個對象也被稱為 int 而 <type 'int'> 只是它打印出來的樣子.

  • 3 <type 'int'> 的type是另外一個叫做 <type 'type'>的對象象.

  • 4 <type 'int'> 的bases屬性是一個tuple,這個tuple包含一個叫 <type 'object'>的對象. 我想你沒考慮過檢查 bases這個屬性 ;).

  • 5 列出這個原始integer對象的所有屬性來 - 好多東西啊.

耐心點先來看我們的第一條規則

規則1
  • 任何東西都是一個object

int 是 object. 這不是說例如2和77這樣的數字是object (他們確實是), 而是說確實有另外一個對象叫做 int ,他處於內存中的實際的整數之外的內存中. 實際上所有的整數對象的class屬性都指向 int,他們共同的心聲是"知我者int也". 在一個object上調用type()方法返回的也正好是這個對象的class屬性的值.

我們定義的所有classes都是對象, 當然這些classes的實例也是對象.甚至我們定義的方法和函數也是對象. 並且像我們看到的,這些對象都有些不同.

 

空白狀態

現在我們來從頭構建python的對象系統. 我們從一個空白狀態開始.

Figure 1.1. 空白狀態

http://www.cafepy.com/article/python_types_and_objects/images/clean_slate.png

你可能在想為啥有兩天灰色的豎線. 后面慢慢來揭曉. 豎線是來區別不同的區域的. 這個空白圖中, 我們來逐漸加上各種對象,畫上他們之間的關系,慢慢畫滿.

這個有助於幫助我們暫且擱置先入為主的各種有關面向對象的類和對象的觀念,以對象的方式(我們這里的對象)來理解一切。

  • At this point, it helps if any preconceived object oriented notions of classes and objects are set aside, and everything is perceived in terms of objects (our objects) and relationships.

 

對象之間的關系

我們使用兩種關系就可以連接我們所引入的這許多不同的對象. 這兩種關系是子類-父類關系 (也可叫做特別化或繼承, 如"人是個動物", 等等.) 和類-實例關系 (也叫實例化, 比如"Joe是個人", 等等.)。

如果你對這些概念已經熟悉了,可以繼續往下看了,否則的話你可能需要先去看看這一部分“面向對象”.

 

2.引入對象

 

第一批對象

我們來查看<type 'object'> 和 <type 'type'>這兩個對象.

Example 2.1. Examining <type 'object'> and <type 'type'>

>>> object 1
<type 'object'>
>>> type 2
<type 'type'> 
>>> type(object) 3
<type 'type'>
>>> object.__class__ 4
<type 'type'>
>>> object.__bases__ 5
()
>>> type.__class__ 6
<type 'type'>
>>> type.__bases__ 7
(<type 'object'>,)

 

 
        
  • 1 2 這是python中兩個最基本對象. 前面我們介紹過用type()來查看一個對象object的類型type(通常就是class屬性的值). 其實,它本身是個對象,並且也是個查看其他對象類型的方式

  • 3 4 5 查看 <type 'object'>: <type 'object'>的類型type是<type 'type'>. 我們也驗證了它的class屬性確實和調用type()是一樣的.

  • 6 7 查看 <type 'type'>: 有趣的是<type 'type'>的type是它自己! 它的bases屬性包含了 <type 'object'>.

下面我們來畫一下所看到的.

Figure 2.1. 雞和蛋的關系

http://www.cafepy.com/article/python_types_and_objects/images/chicken_and_egg.png

圖中兩個對象是python最基本對象. 也可以一次介紹一個,但這里有個雞和蛋一樣的矛盾 - 先介紹哪個好? 這兩個對象是互相依賴的 - 每一個本身都不能單獨存在,都要借助對方來描述自己.

還是繼續我們的python實驗吧:

Example 2.2. 關於 <type 'object'> 和 <type 'type'>的更多內容

>>> isinstance(object, object) 1
True
>>> isinstance(type, object) 2
True

 

  • 1 看看發生了什么? 這是 Dashed Arrow Up Rule 的一個應用. 由於<type 'type'> 是 <type 'object'>的子類, 則<type 'type'> 的實例也是<type 'object'>的實例.

  • 2 將 Dashed Arrow Up Rule 和 Dashed Arrow Down Rule 一起使用, 直接把箭頭反過來也是正確的. (譯注:事實上type,objcet的兩兩組合都是互為instance的)

如果對上面的證明不太理解, 沒關系 - 反正也沒什么用.

再看一個新概念 - 類對象type objects. 我們介紹過的對象都是類對象. 所說的類對象是什么呢? 類對象有如下共同特點:

  • 它們用來代表程序中抽象的數據類型. 例如, 用戶定義的一個叫User的對象可能用來表示系統中所有的用戶,另一個叫int的對象可能代表所有的整數.
  • 它們可以被子類化. 你可以新建一個與已存在的類對象有點類似的新對象.已存在的類對象將成為這個新對象的基類.
  • 它們可以被實例化. 意味着你可以新建一個已存在對象的實例. 這個新對象的class屬性就是已存在對象.

  • 任何類對象的類型是 <type 'type'>.

  • 它們有時被稱為types有時稱為classes.

是的. Types和classes在Python中確實是同一個東西 (免責聲明: 對老式類和早於2.2版本的Python不適用. 那是 types和classes有些不同但那時很久前的事了,現在已這些不同點已經一致了。因此讓過去的事就過去吧,不好嗎?). 不要吃驚,使用type()函數和class屬性得到的是一樣的.

class 這個術語傳統是指被class這個關鍵字創建的class. 內置類型 (比如int和string)通常不和classes聯系起來, 這更多是約定俗成的,實際上types和classes是同一個東西.我覺得這點很重要,可以提出一個規則:

Class is Type is Class
  • type和class這兩個術語在所有Python >= 2.3的版本中是一樣的.

類對象Types 和 (嗯,,讓我想個更好的詞) 非類對象non-types (呵呵!) 都是對象 但只有types可以子類化. Non-types代表的是具體的值所以子類化並沒有意義. 非類對象的兩個例子是整數 2 以及字符串 "hello". 想想,2的子類是什么意思,沒意思吧?

還對判斷類對象和非類對象感覺混淆嗎?有一個簡單的規則:

類和非類對象判斷規則Type Or Non-type Test Rule
  • 如果一個對象是<type 'type'>的實例, 那它就是類對象. 否則是非類對象.

回頭看,可以證明這個規則對我們所碰到的所有對象都是成立的, 包括 <type 'type'>,它是自己的實例.

總結一下:

  1. <type 'object'> 是 <type 'type'>的一個實例.

  2. <type 'object'> 不是任何類的子類.

  3. <type 'type'> 是自己的實例.

  4. <type 'type'> 是 <type 'object'>的子類.

  5. python中只有兩種對象: 為了清楚叫它們types 和 non-types. Non-types 也可以叫實例, 但實例這個術語也可以指向一個類對象, 因為一個type一定是另一個的type的實例. Types 也被叫做 classes, 並且我經常把他們叫做classes.
  • Note that we are drawing arrows on our slate for only the direct relationships, not the implied ones (i.e. only if one object is another's class, or in the other's bases). This make economic use of the slate and our mental capacity.

 

更多內置類型

Python中不止這兩個對象,這兩個基本對象有一堆的兄弟

Figure 2.2. 一些內置類型

http://www.cafepy.com/article/python_types_and_objects/images/builtin_types.png

上面展示了一些內置對象,下面解釋一下.

Example 2.3. 查看一些內置類型

>>> list 1
<type 'list'>
>>> list.__class__  2
<type 'type'>
>>> list.__bases__  3
(<type 'object'>,)
>>> tuple.__class__, tuple.__bases__ 4
(<type 'type'>, (<type 'object'>,))
>>> dict.__class__, dict.__bases__ 5
(<type 'type'>, (<type 'object'>,))
>>>
>>> mylist = [1,2,3] 6
>>> mylist.__class__ 7
<type 'list'>

 

  • 1 內置的<type 'list'> 對象.

  • 2 <type 'list'>的類型是<type 'type'>.

  • 3 它有一個基類 (即 superclass), <type 'object'>.

  • 4 5 類似的還有 <type 'tuple'> 和 <type 'dict'>.

  • 6 創建<type 'list'>的實例的方法.

  • 7 一個list對象的type是 <type 'list>. 不要驚訝.

當創建一個tuple或dictionary對象時, 他們是各自對應類型的實例.

怎樣創建一個mylist的實例呢? 不能. 因為 mylist對象不是一個type.

 

子類化產生新對象

內置對象是內置在python中的. 當我們啟動python的時候就存在,通常程序結束的時候他們還存在.那我們怎樣創建新對象呢?

新對象不會無中生有的出現. 它們必須通過現有的對象來創建.

Example 2.4. 通過子類化構建對象

# Python 2.x:
class C(object): 1
    pass

# Python 3.x, 確定的object基類已經不需要指定了, 默認創建的都是class的基類:
class C: 2
    pass

class D(object):
    pass

class E(C, D): 3
    pass

class MyList(list): 4
    pass 

 

 
  • 1 關鍵字class告訴python通過子類化已有類型來創建一個新類型.
  • 2 不要在Python 2.x中這樣寫,這樣得到的是一個舊式的類old-style class, 這里講的這些在舊式類里都是不適用的.
  • 3 可以有多個基類.
  • 4 多數內置類型都可以被子類化(但不是全部).

從上面的例子可知, C.bases 包含 <type 'object'>, 而 MyList.bases 包含 <type 'list'>.

 

實例化產生新對象

子類化只是產生對象的一種方式,還有另外一種.

Example 2.5. 通過實例化構建對象

 
        
obj = object() 1
cobj = C() 2
mylist = [1,2,3] 3
  • 1 2 調用操作符 (()) 通過實例化已有對象來創建新對象. 這里的已有對象必須是一個類對象type. 對於不同的類對象,這個調用操作符可能接受參數.
  • 2 對某些內置類型python有特殊的語法來創建新對象. 方括號創建 <type 'list'>的實例; 整形數字直接量創建一個 <type 'int'>對象.

有了上面練習的這些, 我們的對象圖就看起來更完美了.

Figure 2.3. 用戶定義對象

http://www.cafepy.com/article/python_types_and_objects/images/user_built_objects.png

注意,僅僅通過子類化 <type 'object'>, 類型C 自動成為 <type 'type'>的實例. 可以通過查看C.class來確認這一點. 下節再對此做解釋.

 

其實都是實例化的

對於這一點你可能會冒出下面這些問題,也可能沒有,不過我還是打算解答一下:

  • Q: python是如何真正創建一個對象的?
  • A: python內部,當創建對象時, 肯定會使用一個type來創建這個type對象的一個實例. 具體的情況是調用這個類對象的new() 和 init() 方法(對這些內容的討論已操作本書范圍). 某種意義上,可以將類對象(type)看做是能夠生產新對象的工廠. 這些生產出來的對象的類型(type)將是創建他們的類對象(type). 這就是為什么每個對象都有個類型type的原因.

  • Q: 當實例化的時候我們指定了類型,但子類化的時候,python如果確定使用什么類型呢?
  • A: 這要看你子類化時指定的基類,將基類的類型type作為新對象(新類)的type,在 Example 2.4, “通過子類化構建對象”這個例子中 , <type 'type'> (指定的基類<type 'object'>的type) 被用做正在創建的C的類型.

想一下就會知道多數iqngk下, <type 'object'>的任何子類 (以及子類的子類,等等)都將被賦予<type 'type'>這個類型.

高級材料展望
  • 一些更高級的討論, 請仔細閱讀, 或者跳到下一節.
  • Advanced discussion ahead, tread with caution, or jump straight to the next section.
  • Q: 我可以指定一個type來替代系統默認的機制嗎?
  • A: 是的,一個可選方案就是用 metaclass 這個類的屬性,如下示例:

Example 2.6. 使用class關鍵字定義類時指定一個type對象

   1 class MyCWithSpecialType(object):
   2     __metaclass__ = SpecialType
  • 這樣Python在創建MyCWithSpecialType時,是實例化 SpecialType的, 而不是<type 'type'>.

  • Q: 太棒了,可以把任意type對象作為metaclass?

  • A: 不是的,指定的元類metaclass必須是所用的基類的type的子類No. It must be a subclass of the type of the base object. 比如上面的例子中:

    • MyCWithSpecialType 的基類是<type 'object'>.

    • <type 'object'>的 type是<type 'type'>.

    • 所以如果用SpecialType metaclass的話, SpecialType必須是 <type 'type'>的子類才行.

    • 使用像SpecialType這樣的東西需要特別小心,這些已經超出本書的范圍.

    • (譯注,

      似乎不是很確切,下面這個例子能運行。也可能是我正好選了個特例吧。
      class Atype(type):
          pass
      class AClass(object):
          __metaclass__ = Atype
      class BClass(AClass):
          __metaclass__ = type

       

       
                  
      • 不過這個特性確實日常用的不多,不用深究了,作者也說超出本書范圍,若有需求再 google吧。)
    • 實測某些情況下,有個元類沖突錯誤the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases)
  • Q: 如果有多個基類,但沒指定metaclass,會使用哪個type對象呢?

  • A: 好問題. 取決於python能否計算出用哪個。若所以基類有相同的type, 就是用這個. 若他們有不同的互不相干的type, python無法算出用哪個. 此時就需要指定一個metaclass, 並且這個metaclass 必須是每個基類的type的共同子類.

  • Q: 我什么時候應該用metaclass?

  • A: 永遠別用 (只要你還問這個問題的話就別用 :)

 

3. 總結一下

 

Python對象圖

最后一章,我們最終得到一個有各種不同python對象的圖

Figure 3.1. Python對象圖

http://www.cafepy.com/article/python_types_and_objects/images/types_map.png

這一節我們也將解釋圖中灰色的豎線是干啥的. 根據人們對不同對象的叫法,灰色豎線將對象圖分成三個區域 - 元類,類和實例.

觀察這個圖可以得出一些學究式的結論
  1. 虛線穿過了區域邊界 (比如,從對象到元對象). 唯一的特例是<type 'type'> (也只能這樣了, 否則就需要在它的左邊再分一個另一個區域,另一個區域左邊還得一個區域等等無窮盡。因為type的type就是自己啊).

  2. 實線不穿過邊界. 又有一個例外, <type 'type'> -> <type 'object'> .

  3. 最右邊的區域不能有實線. 它們是具體的對象,不能子類化.
  4. 虛線的箭頭不能指向最右邊區域. 具體的對象不能再實例化.
  5. 左邊兩個區域包含的是 types. 最右邊區域包含的是non-types.
  6. 如果通過子類化<type 'type'>創建一個對象,它應該放在最左邊的區域。並且它既是<type 'type'>的實例也是<type 'type'>的子類。

Also note that <type 'type'> is indeed a type of all types, and <type 'object'> a superclass of all types (except itself).

  • 也要記住,<type 'type'>確實是所有類對象的type,而<type 'object'> 是所有類對象的超類(除了它自己)。

 

概要

總結一下談到過的內容:

  • python中有兩種對象:
    1. - 可創建實例,可子類化.
    2. Non-type objects - 不能創建實例,不能子類化.
  • <type 'type'>;<type 'object'> 是python系統中的兩個基本對象.

  • 每個對象都有class,並且等於該對象的type.

  • 每個type object有bases屬性, 指向該對象的超類.只有<type 'object'>的bases是空的.

  • 要通過子類化構建對象,我們使用class關鍵字,並指定新對象的基類bases (或者可選的 type) . 這樣通常創建出的是type object.
  • 要通過實例化構建對象, 需要使用在類對象上使用調用操作符即小括號 (())
  • 某些non-type objects可以用特定的python語法創建.比如[1, 2, 3] 創建一個 <type 'list'>的實例.

  • python在內部總是使用一個type object來創建一個新對象。創建出來的新對象是所用的type object的實例。通過class關鍵字創建的type object的類型的確定要看所指定的bases以及bases們的類型。
  • issubclass(A,B) (測試超類-子類關系) ,以下情況返回True:
    1. B在A.bases中,

    2. 對於A.bases中的每一個Z,如果 issubclass(Z,B)為True.(即若A的每個直接基類都是B的子類的話,就可以推導出 A也是B的子類)

  • isinstance(A,B) (測試類型-實例關系) ,以下情況返回True:
    1. BBA.class,

    2. issubclass(A.class,B) 為True.(即若A的類型是B的子類的話,A也就是B的實例)

  • 這樣看來,我的Squasher確實也是蟒蛇. (沒提過,不過現在你就知道了.)

 

好多內置類型還有個名字

Example 3.1. 更多內置 types

>>> import types  1

>>> types.ListType is list 2
True
>>> def f(): 3
...     pass
...
>>> f.__class__ is types.FunctionType 4
True
>>>
>>> class MyList(list): 5
...     pass
...
>>> class MyFunction(types.FunctionType): 6
...     pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: type 'function' is not an acceptable base type
>>> dir(types) 7
['BooleanType', 'DictProxyType', 'DictType', ..]

 

  • 1 types 模塊中包含很多內置類型.
  • 2 一些我們熟知的類型還有另外一個名字.
  • 3 def 創建一個function對象.
  • 4 function對象的類型是 types.FunctionType

  • 5 有的內置類型可以被子類化.
  • 6 但另一些不行.
  • 7 還有更多我們沒了解過的類型.

 

這些有什么意義

我們可以用我們選擇的對象間的關系來創建新對象,但這對我們有什么用?

  • 對象間的關系決定了對象屬性的訪問是怎么起作用的,例如,當使用objectname.attributename,我們得到哪個對象?這完全取決於該對象objectname,它的類型以及它的基類(如果有的話)。

python中的屬性訪問機制在本系列的第二本書中講解:Python Attributes and Methods.

 

經典類型Classic Classes

這是一份關於python中的classic classes 的備忘錄. 用一個空的class關鍵字可以創建老式(早於python2.2)的類.

>>> class ClassicClass: 1
...     pass
...
>>> type(ClassicClass) 2
<type 'classobj'>
>>> import types
>>> types.ClassType is type(ClassicClass) 3
True
>>> types.ClassType.__class__ 4
<type 'type'>
>>> types.ClassType.__bases__ 5
(<type 'object'>,)

 

  • 1 不指定基類的class關鍵字會創建老式的類,注意要創建新式的類必須指定對象作為基類(然而python3.0中不再需要指定基類,因為3.0中默認的就是新式類)。 指定的基類中若只有老式類,那么創建出的也是老式類。若基類中老式的和新式的類都有的話創建出的就是新式的類。
  • 2 這個類型本書中還沒有看到過.
  • 3 老式類的類型是一個叫types.ClassType 的對象.

  • 4 5 看起來它也像是另外一種類對象.

types.ClassType這個對象某種程度上可替代<type 'type'>. 該對象的實例(即老式類) 該對象的實例 (老式類) 也是類對象types. 新老式對象之間的屬性訪問規則是不同的。 types.ClassType 這個對象的存在時為了向后兼容,在將來版本的python中可能就沒有了. 本書的其他部分所講的內容不應被套用到老式類上去。去。

請在這里評論: discussion page. 感謝反饋!

到處結束了,朋友們!

 

4. 可能在其他地方學過的

 

面向對象

可以略過的章節?Can Skim Section

  • (注:這一節英文可能看着更舒服,翻譯起來很費勁,感覺有些術語翻譯了就變味了,盡量看原文吧)

用古怪的一節來講解 類型-實例 和 超類-子類關系

我們引入很多不同的對象,他們之間只用兩種關系就可以概括 ( 4.1. 關系)

  • “是一類” (圖中實線): 即面向對象中的特殊化, 當其中一個(即子類)是另一個(超類)的特殊情況時兩對象間存在這種關系.蛇“是一種”爬蟲. 它具有爬蟲的所有特征並且也有自己作為蛇的一些獨特的特征.

 

      術語: *的子類, *的超類 and 超類-子類.
  • “是一個實例子”(圖中虛線): 也叫實例化, 當其中一個 (即實例)是另一個(即類型)的具體例子時兩對象間存在這種關系. 我有一個寵物蛇叫Squasher. Squasher 是蛇的一個實例.

 

      術語: *的實例, *的類型, 類型-實例 或 類-實例. 

注意在簡單英語中術語,以上兩種關系都可以叫'是一個' . , 蛇是一個爬蟲. 不過我們用特定的術語來避免混淆.

Figure 4.1. 關系

http://www.cafepy.com/article/python_types_and_objects/images/relationships.png

  • 我們用實線表示第一種關系是因為對象之間很接近而不是一個和另一個有關系。例如,如果讓列出和“蛇”最類似的詞,人們很可能會說“爬蟲”。但如果讓列出和 'Squasher'最類似的詞,人們不大可能說“蛇”
  • We use the solid line for the first relationship because these objects are closer to each other than ones related by the second. To illustrate - if one is asked to list words similar to 'snake', one is likely to come up with 'reptile'. However, when asked to list words similar to 'Squasher', one is unlikely to say 'snake'.
  • 基於這點,可以注意到下面的關系的屬性
  • It is useful at this point to note the following (independent) properties of relationships:
  • 虛線向上規則Dashed Arrow Up Rule
    • 如果X是A的實例,A是B的子類,則X也是B的實例.
    虛線規則Dashed Arrow Down Rule
    • 如果B是M的實例,A是B的子類,則A也是M的實例.

換句話說, 虛線箭頭一端可以向上移到實線箭頭,虛線箭尾可以向下移 ( 如Figure 4.2. ""關系的傳遞" 中的2a和2b各自表示的).這些性質可以直接從父類-子類的關系定義得到

Figure 4.2. 關系的傳遞

http://www.cafepy.com/article/python_types_and_objects/images/relationships_transitivity.png

應用 虛線向上規則, 可以從下面第一條描述得到第二條:

  1. Squasher 是蛇的實例 (Squasher的類型是蛇).
  2. Squasher 是爬蟲的實例 (Squasher的類型是爬蟲).

之前我們說過每個對象有一個確切的類型.為啥 Squasher有兩個? 注意雖然每個說法都是正確的, 其中一個更確切 (確切的說可以歸納另一個).也可以說:

  • Squasher.class 是 snake. (Python中, 對象的class指向對象的type).

  • isinstance(Squasher, snake) 和isinstance(Squasher, reptile) 都正確.

父類-子類關系也有個類似的規則.

合並實線規則
  • 若A是B的子類, B是C的子類, 則A也是C的子類

蛇是一種爬蟲, 爬蟲是一種動物. 所有蛇也是一種動物. 或者用Python代碼表示:

  • snake.bases 是 (reptile,). (對象的bases 屬性是一個包含對象超類的元組).

  • issubclass(snake, reptile) 和 issubclass(snake, animal) 都正確.

注意對象可能有不止一個基類.

 

相關資料

 

版權信息

 

This book was written in DocBook XML. The HTML version was produced using DocBook XSL stylesheets and xsltproc. The PDF version was produced using htmldoc. The diagrams were drawn using OmniGraffe [1]. The process was automated using Paver [2].

 

Feedback

請點擊這里評論: discussion page 期待反饋!

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM