我正在编写一个小验证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
是否有可能继承数据结构并在派生类的类级别初始化它而不共享约束的数据结构?
答案 0 :(得分:2)
这个问题分为两部分。
Validatable
类中设置Validatable
数据结构的值;和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。请考虑以下代码,它将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
通过以这种方式使用装饰器,所有初始化在类的定义期间完成一次。