Successfully reported this slideshow.
Your SlideShare is downloading. ×

進階主題

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
從模組到類別
從模組到類別
Loading in …3
×

Check these out next

1 of 61 Ad
Advertisement

More Related Content

Slideshows for you (20)

Viewers also liked (20)

Advertisement
Advertisement

進階主題

  1. 1. 14. 進階主題 • 學習目標 – 運用描述器 – 實作裝飾器 – 定義 meta 類別 – 使用相對匯入
  2. 2. 描述器 • 擁有 __get__() 方法,以及選擇性的 __set__()、__delete__() 方法 • 當描述器成為某個類別的屬性成員時,對 於類別屬性或者其實例屬性的取得、設定 或刪除,將會交由描述器來決定如何處理
  3. 3. • 當 Descriptor 被指定給 Some 類別的 x 屬性時,對於 Some 實例 s 的屬性取值、 指定或刪除,分別相當於進行了以下動作: • 對於 Some.x 這個取值動作,則相當於:
  4. 4. • 資料描述器可以攔截對實例的屬性取得、 設定與刪除行為 • 非資料描述器,是用來攔截透過實例取得 類別屬性時的行為
  5. 5. • 若想控制可以指定給物件的屬性名稱,可 以在定義類別時指定 __slots__ • 這個屬性要是個字串清單,列出可指定給 物件的屬性名稱
  6. 6. • 如果類別定義時指定了 __slots__,那麼 從類別建構出來的實例就不會具有 __dict__ 屬性
  7. 7. • __slots__ 中的屬性,Python 會將之實 作為描述器
  8. 8. • __slots__ 屬性最好作為類別屬性來使用 • 父類別中定義的 __slots__,僅可以透過 父類別來取得,而子類別的 __slots__ 則 僅可以透過子類別來取得
  9. 9. • 若父類別中沒有定義 __slots__,子類別 即使定義了__slots__,以子類別建構出 來的實例,仍然會具有 __dict__ 屬性
  10. 10. • 如果父類別定義了__slots__,而子類別 沒有定義自己的 __slots__,子類別建構 出來的實例也會有 __dict__
  11. 11. • 物件本身可以決定存取屬性的行為 • __getattribute__() 一但定義,任何 屬性的尋找都會被攔截,即使是那些 __xxx__ 的內建屬性名稱 • __getattr__() 的作用,是作為尋找屬 性的最後一個機會
  12. 12. • 取得屬性的順序 – 實例的 __getattribute__() – 資料描述器的 __get__() – 實例的 __dict__ – 非資料描述器的 __get__() – 實例的 __getattr__()
  13. 13. • __setattr__() 的作用,在於攔截所有 對實例的屬性設定 • 設定屬性順序記憶 – 實例的 __setattr__() – 資料描述器的 __set__() – 實例的 __dict__
  14. 14. • __delattr__()的作用,在於攔截所有對 實例的屬性設定 • 刪除屬性順序記憶 – 實例的__delattr__() – 資料描述器的__delete__() – 實例的__dict__
  15. 15. 函式裝飾器 • 裝飾器本質上就是一個函式可接受函式且 傳回函式 • 假設你設計了一個點餐程式…
  16. 16. • 一個函式可以接受函式並傳回函式
  17. 17. • 如果裝飾器語法需要帶有參數,用來作為 裝飾器的函式,必須先以指定的參數執行 一次,傳回函式物件再來裝飾指定的函式
  18. 18. • 除了對函式進行裝飾之外,也可以對類別 作裝飾,也就是所謂類別裝飾器
  19. 19. • 除了使用函式來定義裝飾器之外,也可以 使用類別來定義裝飾器
  20. 20. • 若要使用類別來定義函式裝飾器:
  21. 21. • 若要以定義類別方式,來對函式進行裝飾:
  22. 22. • 若要以定義類別的方式,實作對類別的裝 飾器:
  23. 23. • 可以對類別上定義之方法進行裝飾 • 可以選擇使用函式或者類別來實作 • 方法的第一個參數總是類別的實例本身
  24. 24. • 讓 @log 裝飾的對象,不限於可接受兩個引 數的方法
  25. 25. 認識 type 類別 • 每個物件實例本身都有個 __class__ 屬性 • 類別本身也有個 __class__ 屬性
  26. 26. • 在類別上呼叫 __call__() 會如何呢?
  27. 27. • 使用 type 類別建構類別時,必須指定三個 引數 – 類別名稱(字串) – 類別的父類別(tuple) – 類別的屬性(dict)
  28. 28. • 物件是類別的實例,而類別是 type 的實例 • 如果有方法能介入 type 建立實例與初始化 的過程,就會有辦法改變類別的行為,這 就是 meta 類別的基本概念
  29. 29. • type 是個類別,那麼可以繼承嗎?
  30. 30. • 可以在使用 class 定義類別時,指定 metaclass 為 SomeMeta:
  31. 31. • 繼承了 type 的類別可以作為 meta 類別 • metaclass 是個協定 • 若指定了 metaclass 的類別, Python 在 剖析完類別定義後, 會使用指定的 metaclass 來進行類別的建構與初始化
  32. 32. • 如果使用 class 定義類別時繼承某個父類 別,亦想要指定 metaclass • 使用類別建立物件時:
  33. 33. • 若想改變一個類別建立實例與初始化的流 程,則可以在定義 meta 類別時定義 __call__()方法:
  34. 34. • meta 類別就是 type 的子類別 • 藉由 metaclass = MetaClass 的協定, 可在類別定義剖析完後,繞送至指定的 meta 類別 • 可以定義 meta 類別的 __new__()方法, 決定類別如何建立 – 定義 meta 類別的 __init__(),可以決定類 別如何初始 – 定義 meta 類別的__call__()方法,決定若 使用類別來建構物件時,該如何進行物件的建 立與初始
  35. 35. • metaclass 並不僅僅可指定類別 • 可以指定的對象可以是類別、函式或任何 的物件,只要它具有 __call__() 方法
  36. 36. • 可以定義類別的 __abstractmethods__, 指明某些特性是抽象方法
  37. 37. • 子類別不會看的到父類別的 __abstractmethods__
  38. 38. • Python 實際上還支援相對匯入(Relative import) • 如果想在 xyz.py 中匯入 abc 模組,在 xyz.py 中不能寫 import abc,在 Python 3 中這會是絕對匯入 • 實際上會匯入的是標準程式庫的 abc 模組
  39. 39. • 如果想在 xyz.py 中匯入 mno 模組,在 xyz.py 中不能寫 import mno • 這會引發 ImportError,指出沒有 mno 這個模組 • 如果要使用絕對匯入,必須撰寫 import pkg1.mno • 若要使用相對匯入,則可以撰寫 from . import mno • 如果想使用的是 mno 模組中的 foo()函式, 使用相對匯入的話,還可以撰寫 from .mno import foo 這樣的方式
  40. 40. • 在某個程式中,若 import pkg1 的話, 會執行__init__.py 的內容 • 可以在 pkg1 的 __init__.py 中撰寫: • 只要 import pkg1,就可以直接使用 pkg1.abc、pkg2.mno、pkg1.xyz 來使 用模組了
  41. 41. • 如果想要 import pkg1 之後,可以直接 使用 pkg1.abc、pkg2.mno、pkg1.xyz • 還能直接使用 pkg1.sub_pkg.foo、 pkg1.sub_pkg.orz 模組
  42. 42. • 那麼在 pkg1 的 __init__.py 中,可以撰寫: • 而在 pkg1.sub_pkg 的 __init__.py 中,可 以撰寫:
  43. 43. • 相對匯入只能用在套件之中,如果試圖使 用 python 直譯器執行的某個模組中含有 相對匯入,會引發 SystemError

×