Этот вопрос состоит из двух частей.
- Как установить значения структур данных
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 .Рассмотрим следующий код, который объединяет функцию 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
При использовании декораторов таким способом вся инициализация выполняется один раз во время определения класса.