2011-05-03 59 views
2

我正在編寫一個驗證API併爲類方法中的每個字段初始化約束。但是這種設置主要可以一次性爲班級完成。Python中的繼承但不共享(靜態)類成員

class Demo(Validatable): 

    def __init__(self): 
     Validatable.__init__(self) 
     self.count = 11 

     # could be done at class level 
     self.constrain_field("count", Max(9), Even()) 

但問題是,對於每個字段的限制必須被存儲在某處並且數據結構做到這一點是繼承Validatable類的一部分。所以所有的派生類將共享相同的數據結構,如果約束是在類級別設置的,那麼不應該發生什麼!

class Demo(Validatable): 

    # doesn't work! 
    Validatable.constrain_field("count", Max(9), Even()) 

    def __init__(self): 
     self.count = 11 

是否有可能繼承數據結構並在派生類中的類級初始化它而不共享約束數據結構?

+0

'constraint_field()'是類方法還是靜態方法?它是如何定義的? – brandizzi 2011-05-03 22:17:50

+0

這是一個通常的(實例)方法,但我想改變它。本質上,該方法將約束添加到字典名稱作爲關鍵字和約束作爲值列表。 – deamon 2011-05-04 07:42:13

回答

2

這個問題有兩個部分。

  1. 如何,而不是在繼承Validatable類一組在子類級別Validatable數據結構的值;和
  2. 如何定義constrain_field方法,以便它可以在類初始化時調用一次,而不是每次創建實例。

關於(1)中,Validatable類的初始化可以訪問類使用其__class__屬性的實例的。例如:

class Validatable(object): 
    def __init__(self): 
     self.__class__.fieldName = "value for " + self.__class__.__name__ 

class Demo(Validatable): 
    def __init__(self): 
     super(Demo, self).__init__() 

class Demo2(Validatable): 
    def __init__(self): 
     super(Demo2, self).__init__() 

d = Demo() 
d2 = Demo2() 
print "Demo.fieldName = " + Demo.fieldName 
print "Demo2.fieldName = " + Demo2.fieldName 

此代碼打印:

Demo.fieldName = value for Demo 
Demo2.fieldName = value for Demo2 

constrain_field方法然後可以定義爲使用它被稱爲與該實例的__class__屬性建立必要的數據結構。

不幸的是,這一切都要求在可以設置數據結構之前創建類的實例,這也意味着每次創建實例時都會調用constrain_field方法。顯然,最好在類初始化時做到這一點,這是問題的第(2)部分。

要解決第(2)部分,我會推薦使用python decorators。考慮下面的代碼,一個名爲constrain_field的定製的裝飾功能結合了Python property功能(作爲裝飾):

def Max(maxValue): 
    def checkMax(value): 
     return value <= maxValue 
    checkMax.__doc__ = "Value must be less than or equal to " + str(maxValue) 
    return checkMax 

def Even(): 
    def checkEven(value): 
     "Value must be even" 
     return value%2 == 0 
    return checkEven 

def constrain_field(*constraints): 
    def constraint_decorator(setter): 
     def checkConstraints(self, value): 
      ok = True 
      for c in constraints: 
       if not c(value): 
        ok = False 
        print "Constraint breached: " + c.__doc__ 
      if ok: 
       setter(self, value) 
     return checkConstraints 
    return constraint_decorator 

class Demo(object): 
    def __init__(self): 
     self._count = 2 

    @property 
    def count(self): 
     return self._count 

    @count.setter 
    @constrain_field(Max(9), Even()) 
    def count(self, value): 
     self._count = value 

d = Demo() 
print "Setting to 8" 
d.count = 8 
print "Setting to 9" 
d.count = 9 
print "Setting to 10" 
d.count = 10 
print "Count is now " + str(d.count) 

它打印:

Setting to 8 
Setting to 9 
Constraint breached: Value must be even 
Setting to 10 
Constraint breached: Value must be less than or equal to 9 
Count is now 8 

通過以這種方式使用的裝飾,所有的在類的定義期間初始化完成一次。