day_04: 我不會物件導向


我雖然在 Java 有十多年經驗,但 Python 的物件導向我還尚未深入研究,希望這樣的開頭不會撲滅你的興致,我這篇來分享我在 Python 中看見的物件導向觀點。

Object, 物件

通常在 scripting language 裡頭,物件導向的思維、物件的概念,都跟在一些具有嚴謹類別階層的語言不太一樣。例如在 PyLR 裡頭,第三章談到 object 時,它說:

Objects are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects.

有人說 Python 裡什麼都是物件,這句話對一半。在 Ruby 剛出來時,它也是宣稱什麼都是物件。而 JavaScript 也有人如此宣稱。然而,我認為一個語言要稱自己的物件導向徹底到一個程度,它必須滿足三個條件:

  1. 具備根類別,所有物件都是從根類別衍生出來的,這在 Python 裡,是一個叫 object 的類別
  2. 具備封裝能力,至少能有 public、private、protected 這三種存取控制機制 (其實大多數 scripting language 很難做到這層面,不該苛求啦...)
  3. 透過類別定義而來的多型機制,我可以使用這物件的某個行為 (method),是因為它的類別或介面有定義,而非剛好它有這個函式 (function) (碰過 Ruby 的人,知道我說的正是 duck typing...)

精確地來說,Python 應該說是一個以物件的形式來表現資料的語言,而非一個 everything is object 的語言。

self, 自參考

在物件導向的實作中,大概有這兩種區分屬於類別、屬於物件不同之處。一種是把所有的成員都預設當作物件的,除非特別標示,它才是類別的,像 Java、C# 都是標為 static;另一種是把所有成員都預設成類別的,除非特別傳入自參考 (如:self),或特別指定它與 self 之間的關係,它才會是屬於物件的。

例如這樣:

class Sample:
    static_attr = 1

    def __init__(self):
        self._attr = 0

    def get_attr(self):
        return self._attr

    @staticmethod
    def get_attr_of_class():
        return static_attr

Python 的成員查找邏輯其實可以更複雜,進一步可以參考 淺談 Python 的屬性

既然談到物件與類別成員,我想從另一個角度來分享。

動態定義成員

Python 既然不同於傳統的靜態型別語言,那麼我們對它的期待,一定會是它能動態建立成員內容。這應該怎麼做呢?

例如我們要為剛剛那個 Sample 的物件增加某個屬性,這時可以透過 __setattr__ 來達成:

class Sample:
    def __init__(self):
        pass

    def add_attr(self, name, value):
        self.__attr__(name, value)


sample = Sample()
sample.add_attr('foo', 100)
sample.foo  # 100

如果,從另一個方面來講,有人呼叫了 Sample 未定義的物件,也忘了呼叫 add_attr 怎麼辦?這時候可以搭配 __getattr__ 來使用:

class Sample:
    def __init__(self):
        pass

    def __getattr__(self, name):
        return self.__setattr__(name, 'EMPTY')

sample = Sample()
sample.foo  # EMPTY

當 Python 發現 sample 這個物件沒有 foo 這個屬性時,會自動呼叫 __getattr__,而 __getattr__ 便會透過內定的 __setattr__ 自動增添一個屬性,並賦予預設值 EMPTY

結語

原本在打算著用以往在其他語言開發物件導向的經驗,來看待 Python 物件應當如何,但因為自認為對 Python 的物件導向設計哲學理解甚少而語塞。我希望特別地討論 Python 物件導向特有的面向,避免從其他語言的範式來寫,只是把 sample code 改成 Python。

今天已是第四天,或許我們明天就能開始來思考,在 Python 這個多範式語言裡,能否調和這些範式的特性,發揮各自的作用。不是為了 FP 而 FP,或為了 OOP 而 OOP。

#Python #OOP







你可能感興趣的文章

D11_JS101 綜合題目練習 Lv1

D11_JS101 綜合題目練習 Lv1

JavaScript 核心 - this 到底是誰

JavaScript 核心 - this 到底是誰

MTR04_1012

MTR04_1012






留言討論