iT邦幫忙

2022 iThome 鐵人賽

DAY 4
0

之前說到OO程式設計的實際運作,就是將資料(attributes)和使用這些資料的方法(methods)「封裝」在類別(class)中。今天起我們將逐漸「接地氣」,一步步依次介紹Python如何實作OO的三大支柱封裝、繼承和多型。

  • 封裝的基本原理,上篇已有交代。現在開始寫code。將盡量以Tree()這個類別貫穿全系列文章,遇Tree()不好解釋時換用別的類別說明。
    class Tree():   # class
        def __init__(self, breed, age):  # constructor(建構子/建構式/建構函數/建構方法)
            self.breed = breed    
            self.age = age        
    
  • class是Python的保留字,目的就是定義類別。
  • 上面這段code意思是以class保留字來定義一個名為Tree的類別。注意:Tree的T是大寫。這雖不是語法上的強制,卻是PEP 8的命名規範(註1)。強烈建議乖乖遵從。
  • 這個類別有breed(樹種)和age(樹齡)兩個屬性。就是code中的self.breedself.age
  • 至於使用屬性的「方法」,目前就只有一個:__init__()。這是個特別的方法,OO術語稱為constructor,中文可譯作建構子、建構式、建構函數、建構方法等。筆者通常用建構子,更多時候直接用英文constructor。
  • 維基百科對constructor的解釋如下:

In class-based object-oriented programming, a constructor (abbreviation: ctor) is a special type of subroutine called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables. (摘自wiki)

  • 上面這段英文大意是:constructor是個物件建立時(自動)執行的特殊方法。功能通常是設定該物件屬性的初值,及/或初始化其他資源。

  • 以筆者學過的幾種OO程式語言(可惜號稱最純種的OO語言Smalltalk筆者至今無緣一親芳澤),都有constructor機制。C++除了constructor外,還有destructor。

  • 不同語言,constructor在語法層面自然有所不同。例如C-like這掛語言大概都以「和類別同名且無傳回值」的方法作為constructor。

  • Python的constructor和C-like語言很不一樣,用的是__init__()方法。

  • 本例中的constructor,任務是將傳入的兩個參數breedage賦予給類別的屬性breedage(即self.breedself.age)。請分清楚何者是傳入參數,何者是類別屬性。

  • 傳入的第一個參數self另有用途,以後有專文討論。

  • 一般而言,constructor是在物件建立時,由系統自動執行,而不是由寫程式者呼叫(或稱調用)。

  • 不過Python的constructor__init__() 卻允許由使用者手動呼叫(有些OO語言不可以),呼叫方式和一般物件.方法相同,請參考下面的code。

    class Tree():   # class
        # constructor。當然啦,要允許建立物件時「不傳參數」,那麼這些參數都得有「預設值」才行。
        def __init__(self, breed='', age=-1):  
            self.breed = breed    
            self.age = age 
    
    tree1 = Tree('cedar', 1200)  # 正常做法是在建立物件時就將參數傳給constructor。
    print(f'\n.建立物件時傳遞參數給建構子: {tree1.breed=}, {tree1.age=}\n')
    tree2 = Tree()
    print(f'.建立時沒傳參數給建構子: {tree2.breed=}, {tree2.age=}')
    tree2.__init__('Oak', 580)  # Python允許外部呼叫constructor。
    print(f'.物件建立後才呼叫建構子並傳參數: {tree2.breed=}, {tree2.age=}')
    

    輸出如下:
    https://ithelp.ithome.com.tw/upload/images/20220920/20148485dLUlrApDJB.png

  • 對Python的constructor,「建立物件時系統自動呼叫」及「事後自己外顯呼叫」兩者之間,在功能和效能上是否存在差異,還有待研究。如果事後外顯呼叫沒有明顯優勢,筆者強烈建議讓系統自動幹活,沒必要自己弄髒手。


註1:程式語言中,各種multiple-word identifiers(多字組成的識別符),如變數、常數、函數、類別...等等的名稱,大致有以下幾種「命名慣例」(naming conventions)。略舉耳,未窮盡:

  • Macro Case或Constant Case:
    • 全大寫,兩字間以底線連結,如FAMILY_NAME, USER_LOGIN_ID, REST_API_WEB_APP。這種方式普遍用於常數(constant)。不過Python並無真正的常數,在Python用全大寫來表示常數,只是community間的默契(這回換個詞兒,不說慣例了)。
  • Pascal Case(又稱Upper Camel Case)
    • 組合字每一個字的首字母大寫,其餘小寫。中文稱為「大駝峰」命名方式。例如:FamilyName, UserLoginId, RestApiWebApp
  • Camel Case(又稱Lower Camel Case)
    • 第一個組合字全小寫,第二個字起首字母大寫,其餘小寫。中文稱為「小駝峰」命名方式。例如:familyName, userLoginId, restApiWebApp
  • Snake Case
    • 全小寫,兩個組合字之間用底線_隔開。例如:family_name, user_login_id, rest_api_web_app

PEP 8建議變數和函數用Snake Case,類別則用Pascal Case。


上一篇
OO的幾大支柱
下一篇
3個P's:公開、保護、私有
系列文
Oops! OOPP: An Introduction to Object-Oriented Programming in Python30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言