不管您是否NBA粉絲,只要對籃球界有點認識,NBA史上傳奇控衛--Magic Johnson魔術強生--的大名,總不會陌生吧?告訴大家,原來Python也有Magic,而且不只一位。Python的magic當然不是Magic Johnson,而是magic objects
。講白點就是magic attributes
和 magic methods
。
到目前為止,大家應該可以感受得到,OO就是環繞著類別、屬性、方法,還有公開、保護、私有這幾個概念,以及封裝、繼承、多型等幾大支柱轉來轉去。只要搞清楚這些術語的意義和相互關係,一隻腳大概已跨入OO堂奧。
當然,OO水很深,絕對不只以上這些,往後的篇章筆者將傾盡所知所學,介紹更多觀念和Python的OO上的實作。
__age
是私有屬性。沒有明說,大家用腳趾想也猜到的潛台詞是:有前綴雙底線而無後綴雙底線的方法如__do_private_stuff()
是私有方法。__class__
, __add__()
又是甚麼?答案是:這些長相有點奇怪的屬性和方法,就是剛才說的'magic attributes'
以及'magic methods'
。中文名稱也很直觀,前面加個「魔術」即可。'magic attributes'
是「魔術屬性」,'magic methods'
自然就是「魔術方塊」,不,是「魔術方法」(註2)。"Never invent such names"
。所以,除非是「Python語言本身」的開發者(如Guido van Rossum或其他核心成員),絕大多數僅靠Python糊口混飯吃的芸芸Pythonistas(註3),對這些魔術屬性和方法,了解會用就好,最好自己別嘗試變魔術。不過筆者還是看到有人在變,可能他們想超越劉謙老師吧。
__double_leading_and_trailing_underscore__: “magic” objects or attributes that live in user-controlled namespaces. E.g. __init__, __import__ or __file__. **Never invent such names**; only use them as documented.
class Cult(): # 邪教
def __init__(self, founder: str, name: str):
self.founder = founder # public
self.__name = name # private
self.__name_ = "*".join([char for char in name]) # private
self.__name__ = "+".join([char for char in name]) # 前後綴雙底線,觸犯PEP 8玉律。
def preach(self): # public活動
print(".公開宣揚教義。")
def __grab_money_n_imprison(self): # private偷偷摸摸活動
print(f"{self.__name=}, {self.__name_=}:非法歛財禁錮信眾。")
def __rape_n_rob_n_kill_(self):
print(f"{self.__name=}, {self.__name_=}:奸淫擄掠殘殺無辜。")
def __do_evils__(self): # 以為是private,可為非作歹肆無忌憚,其實早就曝光公諸於世。
self.__grab_money_n_imprison()
self.__rape_n_rob_n_kill_()
__name__
。這只是為了講解之用,PEP 8是不鼓勵的。真正寫code時應盡量避免。
# private屬性測試
cult1 = Cult("麻原彰晃", "奧姆真理教")
print(f"{cult1.founder=}")
cult1.founder = "あさはら しょうこう"
print(f"{cult1.founder=}")
# print(f'{cult1.__name=}') # private,無法存取
# print(f'{cult1.__name_=}') # private,無法存取
print(f"{cult1.__name__=}") # 非private,可以存取,但強烈建議不要變這種戲法。
cult1.__name__ = "Ōmu Shinrikyō"
print(f"{cult1.__name__=}")
print("----------------")
# private方法測試
cult2 = Cult("Jim Jones", "人民聖殿教")
cult2.preach()
cult2.__name = "人民殿堂" # 觀察實際上有無改值。
cult2.__name_ = "Peoples Temple" # 觀察實際上有無改值。
# cult2.__grab_money_n_imprison()
# cult2.__rape_n_rob_n_kill_()
cult2.__do_evils__()
輸出:__name__
前後都有雙底線,成為「魔術屬性」,已經不是私有屬性。可以利用物件.屬性的表示式順利取值和賦值。__do_evils__
是個「魔術方法」,並非私有方法(我猜想其封裝保護層級應為公開),所以可籍由「物件.方法」的表示式去呼叫。而這個方法內,呼叫了兩個私有方法,結果是私有方法的內容曝露於外。如果這不是類別設計者的原意,就是個bug。__
英文稱為dunder
(聽發音),是double underscore的縮寫字。下篇預告:
註1: 「前後都綴雙底線」的更精準說法是「前後都綴最少雙底線」。意思是前綴3條、4條...n條,或後綴3條、4條...n條都算是magic。不是「剛好」兩條才算。
註2: 以筆者找到的資料,Python的「魔術方法」數量上多於「魔術屬性」。所以前後皆綴雙底線的「魔術師」,大部分是「方法」。
註3: Python社群對Python programmers通常有兩個稱謂:pythonista
和pythoneer
(複數當然就是pythonistas和pythoneers)。只要是使用、愛好Python的人,不管職業或業餘,也不管程度如何,即使是剛入門者,通通可稱為pythonista(s)。至於pythoneer(s),則多是對大師級且對Python語言或社群有貢獻的專家的尊稱。
註4: 建構子__init__()
本身也是個魔術方法。