測試開發之Python核心筆記(18): 類與物件入門

2020-08-10 14:40:36

Python是物件導向程式語言。物件導向程式設計中兩個最基本的概念就是類和物件。類是一羣有着相同屬性和函數的一類物件的模板,類範例化後產生物件。在Python中建立一個類和物件是很容易的。

18.1 定義一個類

使用 class 語句來建立一個新類,class 之後爲類的名稱並以冒號結尾,通常類名首字母大寫:
下面 下麪是一個類的例子:

class Document:
	"""
    這是一個文件字串
    """
    # 類變數
    WELCOME_STR = 'Welcome! The context for this book is {}.'

    # 初始化函數,對建立的物件進行初始化,第一個參數是self,不能有返回值
    def __init__(self, title, author, context):
        print('init function called')
        self.title = title  # 成員變數
        self.author = author # 成員變數
        self.__context = context # 成員變數

    # 類函數,常用來實現不同的初始化函數
    @classmethod
    def create_empty_book(cls, title, author):  # 第一參數是cls
    	print(cls.WELCOME_STR)
        return cls(title=title, author=author, context='nothing')

    # 成員函數,第一個參數必須是self
    def get_context_length(self): 
        return len(self.__context)

    # 靜態函數,通常用在類內其他函數中。
    @staticmethod
    def get_welcome(context):
        return Document.WELCOME_STR.format(context)

可以從下面 下麪幾個方面,認識這個類:

  1. 類名是Document,對於Python3,所有類預設都是繼承自object類。
  2. 有一個類變數WELCOME_STR,所有範例化的物件公用的這個類變數。可以在內部類或外部類使用Document.WELCOME_STR 存取。類變數定義在類中且在函數體之外。
  3. __init__是初始化函數,當建立了這個類的範例後就會立即呼叫該方法對範例進行初始化。
  4. self表示這個類的一個範例,所有的實體方法的第一個參數必須是self
  5. __init__是初始化函數,爲範例物件self設定了三個範例屬性,分別是titleauthor__context。範例屬性與類的具體物件相關,每個物件都有自己的屬性,不會像類變數被所有物件共用。
  6. get_context_length是類的一個成員方法,它的第一個參數必須是self。可以存取類變數,呼叫成員方法通常是通過範例化的物件,當然是用類名呼叫也是可以的,不過要傳遞一個物件物件進去。
  7. create_empty_book是類的一個類方法,用@classmethod標識,它的第一個參數必須是cls。類方法可以存取類變數,通常通過類名呼叫。
  8. get_welcome是類的靜態方法,它被設計用來在類內部其他函數中使用,不過在類外部也可以通過類名和範例物件呼叫。

18.2 範例化一個類

範例化類在其他程式語言中一般用關鍵字 new,比如Java語言。但是在 Python 中並沒有這個關鍵字,類的範例化類似呼叫函數一樣,類名加上括號,括號裏面是類的屬性值。

以下使用類的名稱 Document 來範例化,並通過 __init__ 方法接收屬性。

d=Document("demo", "chunming", "show you class")

上面一條語句其實Python是執行兩步:

  1. 呼叫__new__方法建立範例物件。

上面類並沒有__new__方法呀。一般不用自己定義,Python預設呼叫該類的直接父類別的__new__方法來構造該類的範例,如果該類的父類別也沒__new__方法, 那麼將一直按此規矩追溯至object的__new__方法。Document類的直接父類別是object,所以Document類範例化時,是呼叫的object類的__new__方法。看下object的__new__方法是如何定義的:

@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
    """ Create and return a new object.  See help(type) for accurate signature. """
    pass

可見object的__new__方法,是一個靜態方法,通常使用方式是object.__new__。

  1. 緊接着用__init__方法對物件進行初始化。如果沒定義,則不會進行特別的初始化動作。

18.3 存取屬性和方法

範例化類之後,就可以用物件存取類變數、範例屬性、類方法、實體方法和靜態方法了。
在上面的類程式碼檔案中,寫下如下測試程式碼:

if __name__ == '__main__':
    d = Document("demo", "chunming", "show you class")
    print("存取類變數=", d.WELCOME_STR)  # 1.範例物件存取類變數
    d0 = d.create_empty_book("有預設content", "範例物件")  # 2.範例物件呼叫類方法
    print(d.get_welcome("範例物件呼叫靜態函數"))  # 3. 範例物件呼叫靜態方法
    print(d.get_context_length())  # 4. 範例物件呼叫成員方法

    print(Document.WELCOME_STR)  # 5. 類名存取類變數
    # print(Document.title)  # 不可以。
    print(Document.get_context_length(d))  # 6. 類名存取成員方法
    f = Document.create_empty_book("static", "liu")  # 7. 類名存取類方法
    print(Document.get_welcome("aa"))  # 8. 類名存取靜態方法

可以存取類的屬性和方法,都是通過點號方式。 範例物件和類都可以存取類變數、類方法、實體方法和靜態方法。但是類不能存取範例屬性。

18.4 如何檢視類有哪些屬性和方法

有兩種辦法可以檢視類有哪些屬性。

  • 第一個辦法,dir(類名),會顯示由屬性的名字組成的列表。
['WELCOME_STR', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'create_empty_book', 'get_context_length', 'get_welcome']
  • 第二個辦法,類名.__dict__,是一個字典,包含屬性的名字和值
{'__module__': '__main__', '__doc__': '\n    這是一個文件字串\n    ', 'WELCOME_STR': 'Welcome! The context for this book is {}.', '__init__': <function Document.__init__ at 0x1101f9f80>, 'create_empty_book': <classmethod object at 0x110260750>, 'get_context_length': <function Document.get_context_length at 0x11025d710>, 'get_welcome': <staticmethod object at 0x110260790>, '__dict__': <attribute '__dict__' of 'Document' objects>, '__weakref__': <attribute '__weakref__' of 'Document' objects>}

從dir函數和__dict__的輸出可以看出,有些屬性我們在Document類中並沒有定義,比如__module____class____dict__以及__doc__等,這些屬性是Python爲每一個類自動設定的。

  • C.__name__,表示類C的名字
  • C.__dict__ ,表示類C的屬性以及值。
  • C.__module__,表示類C的定義所在的模組名稱,獨立執行模組時爲字串__main__。模組被匯入時,被設定爲模組的名稱。
  • i.__class__,表示範例i所屬的類
  • C.__bases__,表示類C的所有直接父類別組成的元組,不包括父類別的父類別
  • C.__doc__,表示類C的文件字串。

18.5 類中的方法

  • 構造方法
  1. __init__ 表示建構函式,對生成的物件進行初始化操作,一個物件生成後會被自動呼叫的函數。
  • 成員方法
  1. 物件的某個動態能力,比如上述程式碼中的get_context_length函數,函數的第一個參數是self。
  • 靜態方法
  1. 在函數前一行加上@staticmethod表示
  2. 靜態方法則與類沒有什麼關聯,用來單獨完成些任務,可以在多個成員方法中使用。
  • 類方法
  1. 第一個參數一般爲 cls,表示必須傳一個類進來。需要裝飾器 @classmethod 來宣告。
  2. 常用的場景是實現不同的__init__ 建構函式,比如上文程式碼中,我們使用 create_empty_book 類函數,來創造新的書籍物件,用它來創造的書籍其 context 一定爲 ‘nothing’。

好了。Python類與物件入門就介紹到這裏。下一小節我們繼續對屬性進行輸入介紹。