如何使用Python繼承機制(子類化內建型別)

2020-07-16 10:05:02
我們知道,Python 中內建有一個 object 類,它是所有內建型別的共同祖先,也是所有沒有顯式指定父類別的類(包括使用者自定義的)的共同祖先。因此在實際程式設計過程中,如果想實現與某個內建型別具有類似行為的類時,最好的方法就是將這個內建型別子類化。

置型別子類化,其實就是自定義一個新類,使其繼承有類似行為的內建類,通過重定義這個新類實現指定的功能。

舉個例子,如下所示建立了一個名為 newDict 的類,其中 newDictError 是自定義的異常類:
class newDictError(ValueError):
  """如果向newDict 新增重複值,則引發此異常"""

class newDict(dict):
  """不接受重複值的字典"""
  def __setitem__(self,key,value):
    if value in self.values():
      if ((key in self and self[key]!=value) or (key not in self)):
        raise newDictError("這個值已經存在,並對應不同的鍵")
    super().__setitem__(key,value)
demoDict = newDict()
demoDict['key']='value'
demoDict['other_key']='value2'
print(demoDict)
demoDict['other_key']='value'
print(demoDict)
執行結果為:

{'key': 'value', 'other_key': 'value2'}
Traceback (most recent call last):
  File "C:UsersmengmaDesktopdemo.py", line 15, in <module>
    demoDict['other_key']='value'
  File "C:UsersmengmaDesktopdemo.py", line 9, in __setitem__
    raise newDictError("這個值已經存在,並對應不同的鍵")
newDictError: 這個值已經存在,並對應不同的鍵

可以看到,newDict 是 Python 中 dict 型別的子類,所以其大部分行為都和 dict 內建類相同,唯一不同之處在於,newDict 不允許字典中多個鍵對應相同的值。如果使用者試圖新增具有相同值的新元素,則會引發 newDictError 異常,並給出提示資訊。

由於目前尚未學習如何處理異常,因此這裡沒有 newDictError 做任何處理,例外處理會在後續章節做詳細講解。


另外,如果檢視現有程式碼你會發現,其實很多類都是對 Python 內建類的部分實現,它們作為子類的速度更快,程式碼更整潔。

比如,list 型別用來管理序列,如果一個類需要在內部處理序列,那麼就可以對 list 進行子類化,範例程式碼如下:
class myList(list):
  def __init__(self,name):
    self.name = name

  def dir(self,nesting = 0):
    offset = " " * nesting
    print("%s%s/" % (offset,self.name))

    for element in self:
      if hasattr(element , 'dir'):
        element.dir(nesting + 1)
      else:
        print("%s %s" % (offset,element))

demoList = myList('C語言中文網')
demoList.append('http://c.biancheng.net')
print(demoList.dir())
執行結果如下:

C語言中文網/
http://c.biancheng.net
None

其實,除了 Python 中常用的基本內建型別,collections 模組中還額外提供了很多有用的容器,這些容器可以滿足大部分情況。