Python中的继承但不是共享(静态)类成员

时间:2011-05-03 21:19:32

标签: python oop

我正在编写一个小验证API并初始化类__init__方法中每个字段的约束。但是这种设置主要可以在课堂上进行一次。

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

是否有可能继承数据结构并在派生类的类级别初始化它而不共享约束的数据结构?

1 个答案:

答案 0 :(得分:2)

这个问题分为两部分。

  1. 如何在子类级别而不是在继承的Validatable类中设置Validatable数据结构的值;和
  2. 如何定义constrain_field方法,以便在类初始化时调用一次,而不是每次创建实例时都调用它。
  3. 关于(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。请考虑以下代码,它将Python property函数(用作装饰器)与名为constrain_field的自定义装饰器函数相结合:

    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
    

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