1. 程式人生 > 程式設計 >Python如何定義有可選引數的元類

Python如何定義有可選引數的元類

問題

你想定義一個元類,允許類定義時提供可選引數,這樣可以控制或配置型別的建立過程。

解決方案

在定義類的時候,Python允許我們使用 ``metaclass``關鍵字引數來指定特定的元類。 例如使用抽象基類:

from abc import ABCMeta,abstractmethod
class IStream(metaclass=ABCMeta):
  @abstractmethod
  def read(self,maxsize=None):
    pass

  @abstractmethod
  def write(self,data):
    pass

然而,在自定義元類中我們還可以提供其他的關鍵字引數,如下所示:

class Spam(metaclass=MyMeta,debug=True,synchronize=True):
  pass

為了使元類支援這些關鍵字引數,你必須確保在 __prepare__() ,__new__() __init__() 方法中 都使用強制關鍵字引數。就像下面這樣:

class MyMeta(type):
  # Optional
  @classmethod
  def __prepare__(cls,name,bases,*,debug=False,synchronize=False):
    # Custom processing
    pass
    return super().__prepare__(name,bases)

  # Required
  def __new__(cls,ns,synchronize=False):
    # Custom processing
    pass
    return super().__new__(cls,ns)

  # Required
  def __init__(self,synchronize=False):
    # Custom processing
    pass
    super().__init__(name,ns)

討論

給一個元類新增可選關鍵字引數需要你完全弄懂類建立的所有步驟, 因為這些引數會被傳遞給每一個相關的方法。 __prepare__() 方法在所有類定義開始執行前首先被呼叫,用來建立類名稱空間。 通常來講,這個方法只是簡單的返回一個字典或其他對映物件。 __new__() 方法被用來例項化最終的類物件。它在類的主體被執行完後開始執行。 __init__() 方法最後被呼叫,用來執行其他的一些初始化工作。

當我們構造元類的時候,通常只需要定義一個 __new__() __init__() 方法,但不是兩個都定義。 但是,如果需要接受其他的關鍵字引數的話,這兩個方法就要同時提供,並且都要提供對應的引數簽名。 預設的 __prepare__()

方法接受任意的關鍵字引數,但是會忽略它們, 所以只有當這些額外的引數可能會影響到類名稱空間的建立時你才需要去定義 __prepare__() 方法。

通過使用強制關鍵字引數,在類的建立過程中我們必須通過關鍵字來指定這些引數。

使用關鍵字引數配置一個元類還可以視作對類變數的一種替代方式。例如:

class Spam(metaclass=MyMeta):
  debug = True
  synchronize = True
  pass

將這些屬性定義為引數的好處在於它們不會汙染類的名稱空間, 這些屬性僅僅只從屬於類的建立階段,而不是類中的語句執行階段。 另外,它們在 __prepare__() 方法中是可以被訪問的,因為這個方法會在所有類主體執行前被執行。 但是類變數只能在元類的 __new__()__init__() 方法中可見。

以上就是Python如何定義有可選引數的元類的詳細內容,更多關於Python定義元類的資料請關注我們其它相關文章!