2011-05-03 61 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 

通过以这种方式使用的装饰,所有的在类的定义期间初始化完成一次。