Python進階技巧 (2) — Static/Class/Abstract Methods之實現

Jack Cheng
整個程式都是我的咖啡館
12 min readOct 22, 2018

--

「如何在 Python 上實現 Static/Class/Abstract methods?!」

難易度:★★★☆☆(有學習過Object Oriented相關內容、對 Python Class 概念熟悉者較易上手)

實用度:★★★★☆

By pixabay.com

【導言】

Static 、Abstract和 的概念相信有學過 Object Oriented Language 相關內容的人都不陌生,以下基於篇幅關係都先認定大家有一定程度的了解,所以概念與定義的部份會簡單帶過,不多著墨。

Python 在 Method 的部份有四大類:

  • Instance method:實例方法,即帶有 instance 為參數的 method,為大家最常使用的 method
  • Static method:靜態方法,不帶 instance 以及 class 為參數的 method
  • Class method:類方法,帶有 class 為參數的 method
  • Abstract method:抽象方法,尚未被實作且 children class 一定要用 override來實作之,用來實現類似 Java interface 或 C++ pure virtual function

以下會解說後面三種較為不常見的 method,其中對於其他語言的類比是幾乎不可能100%相同,只能盡量從其他語言相似的概念來對照解說,讀者還是要知道 Python 自己語言本身的特性與概念,盡量不要混淆了~

【開發環境與建議先備知識】

OS Ubuntu 16.04

Python 3.6

Required Knowledge

  • Familiar with Python Class (instance, override, metaclass, inheritance, initializer …)
  • Python Decorator
  • Object Oriented Language Basics (static, abstract, interface, polymorphism…)

【壹、Python 的 Static Method】

1. 複習一下什麼是 static ?!

以 Java 為例(對於大多數語言static的核心概念是相似的),一個 member 被宣告為 static 代表該 member 是在 Class Initialization 階段就被寫在一塊記憶體上,因為是發生在 Instance Initialization 前,所以理所當然不會帶有 instance,且該 static member 之參數必須也是 static的(不然根本拿不到)。而該 class 所生之所有 instances 皆可以使用該 static member 。

總結,使用 static 的時機有:

  • Design 意義上,希望某個 member independent of instance,不帶instance為參數,就會宣告該 member 為 static ,使 members 間的關係更加乾淨俐落。
  • Design 意義上,希望某個 variable 是 static 的代表,想要該 class 所生之所有 instances 共用相同值的參數,作為 instances 間的溝通與合作。
  • Physical 意義上,一個 static member 因為是只使用到一塊記憶體,故 instances 無論多寡,該 static member 所佔空間都不會增加。

2. static method 範例講解

範例中,Python只需要添加 @staticmethod 這個 decorator在method上就相當於宣告這個method是static了!

由上述例子可以知道:

  • static method 不需要也不能將 instance 以參數 self 的方式傳入
  • static method 可以由 class 直接 call 而不一定需要用到 instance call
  • static method 也可以由 instance (例子中的 black_shiba) call,但是是不帶有 instance參數的。

【貳、Python 的 Class Method】

1. 什麼是 class method ?!

這個詞在 Object Oriented 中的概念和在 Python 不太一樣,在這邊先釐清一下 xD

在 Object Oriented 中,一般來說,一個 class 裡面的所有 method 都叫做 class method!但在 Python 裡,有一個概念特別獨立出來稱為 class method ,是當一個 method 是帶有 class 本身作為參數傳入時,我們稱之為 class method,當然 Python 也已經提供 decorator @classmethod 給我們用囉,很方便對不對!

所以以後在跟別人講到這個詞的時候,要特別小心彼此間的溝通,到底是不是在講同一個東西!這件事在 Programming Language 太常發生,溝通時一定要搞清楚兩人是不是在同一個宇宙裡對話 QQ

2. class method 範例講解

範例中,Python 只需要添加 decorator @classmethod在method前即可宣告該method 為 static。

由上述例子可以知道:

  • class method 必須傳入 class 本身作參數:即例子中的 cls ,這個參數的名稱理論上是可以自由命名的,但一般來說我們都會命名為 cls(代表class 縮寫),就如同 instance method (一般 method)都會以 self 作為傳入 instance 參數的命名一樣。
  • 和 static method 一樣,class method 也可以由 instance call:在例子中 instance black_shiba 一樣可以 call .pee()
  • 和 static method 不同,class method 可以藉由 cls class 本身去 access class static members(variable/method):在這個例子中,pee_length 即為 class Shiba 的 static variable,所以 class method 可以利用 cls.pee_length 去 access 到 pee_length 。但若是 static method 的話就無法了,static method 因為沒有 selfcls ,根本無法 access 放在外面的 static member,會直接噴 error:

【三、Python 的 Abstract Method】

1. 什麼是 abstract method ?!

來到要介紹的最後一種 method,abstract method。

首先澄清一下,如果熟悉 Object Oriented 概念的人一定知道什麼是 polymorphism (多形)的概念,在 Java 上簡單來說就是以 interface 實現,而在 C++ 上是以 pure virtual function 實現。

Polymorphism 是 OOP 中重要的 design ,有以下幾個最重要的優點:

  • 增加 programming 的維護性:使用 polymorphism 相當於把該 object 的接口都定義好,讓其他 object 在 inherit 或是 implement 時有一個「代辦清單」,而且是一個「定義嚴謹的代辦清單」(裡頭包含 input/output 的 type 等等)。
  • 減低 object 彼此的依賴度:舉例來說,原本 A 、B 和 C 三個 objects (classes) 都要實作 吃大便()喝飲料() 這兩個 method,為了展現 A 、B 和 C是有關係的,所以會採用 inheritance 方式去實作,即 B inherits A,C inherits B,某天當 A 要做改變時,就會連帶影響 B 和 C。如果今天採用polymorphism 的方式設計,相當於「把結構從鏈狀、上下游的裙帶關係」轉成「只有一個控制中心而底下為平行關係」,這樣儘管今天 A 要做修改,也不會影響到 B 和 C。這只是一個小小的例子,還有各種排列組合的例子不勝枚舉,在此只做簡短解說,就不一一說明了。

2. abstract method 範例講解

押在最後解說,代表其困難度比較高 xDD

實現 abstract method 有兩種方式,一種較為寬鬆(只在 call method 時才去檢查 abstract method 是否已經被 implemented),另一種較為嚴謹正規(在 class initialization 時即會檢查 abstract method 是否已經被實作)。

我們這裡只介紹後者,較為嚴謹正規的實作方法。先下一段 code 再慢慢解說~

首先,要先 import abc (Abstract Base Classes)這個 lib,放心這是 Python 的標準庫,基本上安裝 Python 時都已經被安裝好。

概念上我把 Dog class 純粹當作 polymorphism 的 interface 來操作,所以裡頭的 methods 全部都寫成 abstract methods。另外,由例子可以知道 DogShiba 的 Parent class (Base class)。

如何建立 abstract methods 呢?先將 class 的 metaclass 設成 abc.ABCMeta ,並且直接在 method 上添加 @abc.abstractmethod 就可以將該 method 變成 abstract 了!(當我們在某個 method 上加 @abc.abstractmethod 時,預設為 abstract instance method 唷!若想要變成 abstract instance method 文章後面會解說~)當我們在最後一行 code 中 initialize Shiba 這個 class 時,就會因為我們沒有 override abstract methods (去實現這個 abstract method)而噴 error。

不知道什麼是 metaclass ?! 可以參考本文章最下面附上的參考連結,不過先打劑預防針,除非是對 Python OOP 熟悉的人,否則應該是會讀得有些痛苦,這裡就先帶過,之後會再出一篇文章解說看看~

明白如何建立 abstract method 後,我們來實作一個超迷你的 polymorphism 例子吧!給範例:

由上述例子可以知道,我將 Dog 作為 interface ,讓 Shiba 以 inherit 的方式並且 override eat_shit()pee() 這兩個 methods,這樣就達到實作 interface 的效果了!!!

另外複習一下,Python 本身沒有 override 的額外語法,而是採用 children class 中宣告相同 method name 就當作直接 override 喔!

3. abstract members 範例解說

最後補充一些,除了上面 abc lib 所提供的 abstract method 外,舊版本(v3.2以下)還有支援另外三種 abstract members:

  • @abc.abstractstaticmethod
  • @abc.abstractclassmethod
  • @abc.abstractproperty

當中 @abc.abstractstaticmethod@abc.abstractclassmethod 其實就只是把 abstract 做在前面提過的 static method 和 classmethod 上而已,聰明的大家一定已經有能力摸索了。而 @abc.abstractproperty 用狗的屁股想也知道是把 abstract 做在 property 上,至於 property 是什麼東東,因為篇幅關係只能留在之後的文章細談囉 xDDDDD

但是,新版本(v3.3以上)都已經全面丟掉這些語法了!(請參考官方文件)相信現在大多數的人都早就不是在舊版本的環境了。現在新版全面以「組合」的方式取代之:

  • @abc.abstractstaticmethod = @static.method +@abc.abstractmethod
  • @abc.abstractclassmethod = @class.method +@abc.abstractmethod
  • @abc.abstractproperty = @properties +@abc.abstractmethod

以下快速給出使用範例,大家自己玩玩吧:

以上範例中,請一定要注意 decorators 的擺放順序!!!

@static.method +@abc.abstractmethod 代表 @static.method 在前 @abc.abstractmethod 在後,不可以顛倒放,否則會出錯!至於原因就必須好好解說 decorator 的運作原理,這會在之後的文章再給大家補充的(大家能看到這邊應該也累了)!

【結語】

從文章開始到最後,會發現這些語法可以排列組合,做出不同的 Object Oriented Programming 當中的幾個重要概念,其實代表 Python 在設計的時候確實是「比較好入門」,但不代表就是「比較簡單」,很多重要概念並沒有要求初學者立刻學會,但其實很多概念都是可以實作出來。

例外,這邊提供大家利用 Python 學習與實作 OOP 當中的各種技巧,不是一味推崇 OOP ,畢竟現在也有一派傾軋 OOP 許多地方的聲音,主要是提供大家可以用的工具們,大家還是得自己分析什麼樣的場合、情境、資源和專案適合使用什麼樣的工具與技巧囉!

最後一個概念留給大家實作:做出 Abstract Class 吧!!

這個也是 Object Oriented Programming 裡的概念,大家就遵照定義,自己實作出一個 Abstract Class 吧!(應該可以秒殺吧 xDDD)

這篇文章的難度確實比較高,許多重要概念也都是放在未來的文章中解說,無法在有限篇幅下解說每一個細節,請大家多見諒。不懂的地方也可以先擱著,等未來更加熟悉 Python 和 Object Oriented Programming 後再回頭複習也不錯,如果當場都能夠理解消化的話就代表你的底子有學紮實或是你是相關背景出身的了!

【飯後餐點】

特別感謝阿玉(Jade Chen)校稿斧正本文章。

最後附上一些延伸相關資料。

如果你也喜歡我們的文章,幫我們動動手部肌肉,按下掌聲Clap,讓我們有動力繼續煮下一頓料理!

--

--

Jack Cheng
整個程式都是我的咖啡館

Interested in ML, algorithms, and back-end. Studied M.S. at NTU GICE.