2010-12-20 54 views
4


我有一個基類,從中派生出多個子類。
每個子類都定義了類常量,我希望對它們實施某些限制。 例如:派生自動類裝飾(或驗證)

class Base(object): 
    # define these in your sub-class, and make sure (NOM % DENOM == 0) 
    NOMINATOR = None 
    DENOMINATOR = None 

class Subclass_good(Base): 
    NOMINATOR = 6 
    DENOMINATOR = 3 

class Subclass_bad(Base): 
    NOMINATOR = 7 
    DENOMINATOR = 5 

我希望能夠強制執行規則(NOM%DENOM == 0)。
我目前做了一類裝飾:

def nom_denom_validator(cls): 
    assert(cls.NOMINATOR % cls.DENOMINATOR == 0) 
    return cls 

# and decorate each subclass, e.g.: 
@nom_denom_validator 
class Subclass_another(Base): 
    NOMINATOR = 9 
    DENOMINATOR = 12 

但我不喜歡這樣的事實,我需要裝點每個子類(我有很多)。我感興趣的是,這是否可以通過對Base類的某些操作直接完成。

有什麼建議嗎?

回答

8

好吧,好笑。我想了一會兒,但是隻有在發佈問題之後 - 特別是在選擇標籤時,並在其中添加「元類」 - 我才意識到自己可能會有一個答案。
因此,提交審查和未來的知識,這裏有雲:

class Base_Metaclass(type): 
    def __new__(meta, classname, bases, class_dict): 
     new_type = type.__new__(meta, classname, bases, class_dict) 
     if not (new_type.NOMINATOR % new_type.DENOMINATOR) == 0: 
      raise Exception("Invalid subclass created - validation failed") 
     return new_type 

# have Base and all its descendants be enforced: 
class Base(object): 
    __metaclass__ = Base_Metaclass 
    # I must pass the validation myself, no None's anymore... 
    NOMINATOR = 1 
    DENOMINATOR = 1 

而現在所有的孩子都應該被自動執行。

+4

是的,如果你想要繼承類級別的行爲,你需要一個元類。如果你不'想要它繼承,你想要一個類裝飾器。 – Steve 2010-12-20 13:44:46

1

你可以檢查在基類的構造函數

class Base(object): 
    # define these in your sub-class, and make sure (NOM % DENOM == 0) 
    NOMINATOR = None 
    DENOMINATOR = None 
    def __init__(self): 
     assert(self.NOMINATOR % self.DENOMINATOR == 0) 

當您創建的Subclass_bad()一個實例,你會得到AssertionError

+0

這確實可以防止不好的情況,但我期望在編譯時防止創建無效的子類本身。 – Yonatan 2010-12-20 13:39:36

+0

編譯時你不能這樣做:編譯時你會發現語法錯誤,但是metaclass解決方案會檢查類是在運行時定義的,還是檢查基類的構造函數將檢查實例的何時也是在運行時創建的。 – Duncan 2010-12-20 14:27:10

+0

@Duncan:當然你是對的。我在導入時引用了類對象定義,這絕對是在運行時。 – Yonatan 2010-12-20 16:22:48