使用類別與物件 V.S. 模組的時機

以下是決定何時該將程式放入類別或模組的準則

  • 當需要許多實例,且它們有類似的行為(方法),但內部的狀態不同(屬性)時,物件是最實用的選擇
  • 類別可繼承,模組不行
  • 如果某個東西只需要一個,模組可能是最好的選擇
    • 無論程式參考某個 Python 模組幾次,它都只會載入一個複本
    • 給 Java 與 C++ 程式員:如果對 Erich Gamma 寫的 Design Patterns: Elements of Reusable Object-Oriented Software 這本書很熟的話,可以將 Python 模組當成一個單例(singleton)
  • 如果有許多變數,它們裡面有許多值,而且這些值可以當成引數傳給多個函式,將它們定義成類別可能比較好
    • 例如,或許會用一個字典,裡面有代表彩色圖像的 size 與 color 等鍵
    • 可以在程式中為每一個圖像建立不同的字典,並將它們當成引數傳給 scale() 或 transform() 等函式
    • 當加入鍵與函式時,可能會很亂 → 比較一致的作法是:定義一個 Image 類別,並在裡面加入 size 或 color 屬性,及 scale() 與 transform() 方法
    • 於是,就可以將「彩色圖像的資料」與「方法」定義在同一個地方
  • 使用最簡單的問題解決方式
    • 字典、串列與 tuple 都比模組更簡單、更小,且更快
    • 模組通常比類別簡單

Guido 的建議

-- Guido van Rossum(https://plus.google.com/u/0/115212051037621986145/posts/HajXHPGN752)

  • 避免過度設計資料結構
  • Tuple 比物件好(試試具名 tuple)
  • 簡單的欄位比 getter/setter 函式好 → 內建的資料類型是你的好朋友
  • 儘量使用數字、字串、tuple、串列、集合、字典
  • 也試試使用集合、程式庫,特別是 deque

Some patterns for fast Python. Know any others?

  • Avoid overengineering datastructures. Tuples are better than objects (try namedtuple too though). Prefer simple fields over getter/setter functions.

  • Built-in datatypes are your friends. Use more numbers, strings, tuples, lists, sets, dicts. Also check out the collections library, esp. deque.

  • Be suspicious of function/method calls; creating a stack frame is expensive.

  • Don't write Java (or C++, or Javascript, ...) in Python.

  • Are you sure it's too slow? Profile before optimizing!

  • The universal speed-up is rewriting small bits of code in C. Do this only when all else fails.

具名 Tuple

  • 關於「具名 Tuple」

    • 因為 Guido 剛才提到它,本書還沒談到,所以這裡很適合討論 具名 tuple(named tuple)
    • 具名 tuple 是一種 tuple 的子類別,其中,可以用名稱(使用 .name),以及位置(使用[ offset ])來存取值
  • 將之前範例的「Duck 類別」轉換成「具名 tuple」

    • 使用 bill 與 tail 來作為簡單的字串屬性
    • 在呼叫 namedtuple 時會使用兩個引數:
      • 名稱
      • 欄位名稱字串,以空格分開

【範例】具名 Tuple

# Python 並不會自動提供具名 tuple,所以在使用它們之前,必須先載入一個模組 → 在以下範例的第一行做這件事
>>> from collections import namedtuple
>>> Duck = namedtuple('Duck', 'bill tail')
>>> duck = Duck('wide orange', 'long')
>>> duck
Duck(bill='wide orange', tail='long')
>>> duck.bill
'wide orange'
>>> duck.tail
'long'


# 可以用字典來製作具名 tuple
>>> parts = {'bill': 'wide orange', 'tail': 'long'}
>>> duck2 = Duck(**parts)
>>> duck2
Duck(bill='wide orange', tail='long')


# 看一下程式中的 **parts。這是一個關鍵字引數 → 它會取用部份的字典鍵與值,並將它們當成引數傳給 Duck()
# 它的效果相當於:
>>> duck2 = Duck(bill = 'wide orange', tail = 'long')


# 具名 tuple 是不可變的,但可以更換一或多個欄位,並回傳另一個命名 tuple
>>> duck3 = duck2._replace(tail='magnificent', bill='crushing')
>>> duck3
Duck(tail='magnificent', bill='crushing')


# 可以將 duck 定義為字典
>>> duck_dict = {'bill': 'wide orange', 'tail': 'long'}
>>> duck_dict
{'bill': 'wide orange', 'tail': 'long'}


# 可以將欄位加入字典
>>> duck_dict['color'] = 'green'
>>> duck_dict
{'color': 'green', 'bill': 'wide orange', 'tail': 'long'}


# 而不是加到具名 tuple
>>> duck.color = 'green'
Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    duck.color = 'green'
AttributeError: 'Duck' object has no attribute 'color'

總之,以下是具名 tuple 的優點

  • 它的外觀與行為都像個不可變物件
  • 它比物件更節省空間與時間
  • 可以用「句點標記法」取代「字典型式的方括號」來存取屬性
  • 可以將它當成字典鍵來使用

results matching ""

    No results matching ""