我想验证对象初始化后的两个字段。我使用attrs定义元类PropertyMeta,然后在另一个类PropertyDescriptor中使用PropertyMeta。
class PropertyMeta(type):
EXPECTED_VARS = ('PROPERTIES', 'PROPERTY_DEFAULTS',
'PROPERTY_VALIDATORS', 'PROPERTY_CONVERTERS')
@classmethod
def _get_attrib(mcs, property_name, attrs):
kwargs = {}
if property_name in attrs['PROPERTY_DEFAULTS']:
kwargs.update(default=attrs['PROPERTY_DEFAULTS'][property_name])
return attr.attrib(**kwargs)
def __new__(mcs, name, bases, attrs):
if 'PROPERTIES' not in attrs:
attrs['PROPERTIES'] = []
else:
# For the defaults, converters, and validators ensure that extra attributes are not passed.
# If they are defined, set the default value as an empty dict.
for expected_attr in mcs.EXPECTED_VARS:
if expected_attr == 'PROPERTIES':
continue
if expected_attr in attrs:
for arg in attrs[expected_attr]:
if arg not in attrs['PROPERTIES']:
raise ValueError(
"Found a '%s' for an attribute '%s' in '%s' that doesn't belong to 'PROPERTIES';"
" ('PROPERTIES': %r, '%s': %r)" %
(arg, expected_attr, name,
attrs['PROPERTIES'], expected_attr, attrs[expected_attr])
)
else:
attrs[expected_attr] = {}
# Create class from attr with all required attributes. This will set properties in same format as specified
# by attr.
new_cls = attr.make_class(name,
{property_name: mcs._get_attrib(property_name, attrs) for property_name in
attrs['PROPERTIES']})
# Merge the attr class to present class.
return super(PropertyMeta, mcs).__new__(mcs, name, (new_cls,) + bases, attrs)
@six.add_metaclass(PropertyMeta)
class PropertyDescriptor(object):
def __init__(self):
print("Not getting called.")
def __setattr__(self, property_name, property_value):
# Convert properties to appropriate types if specified.
if property_name in self.PROPERTY_CONVERTERS:
property_value = self.PROPERTY_CONVERTERS[property_name](
property_value)
# Validate property values.
if property_name in self.PROPERTY_VALIDATORS:
try:
validator = self.PROPERTY_VALIDATORS[property_name]
validator(self, property_name, property_value)
except Exception as err:
raise err
super(PropertyDescriptor, self).__setattr__(property_name, property_value)
我正在尝试使用PropertyDescriptor作为基类实例化一个对象。每当我的对象被实例化时,PropertyDescriptor的 init 都不会被调用。
从PropertyDescriptor继承的示例。
class Example(PropertyDescriptor):
def __init__(self, **kwargs):
super(A, self).__init__(**kwargs)
print(self.__dict__)
a = Example(start_time=1, end_time=2)
Example类的init 被调用。因此,我可以验证开始时间始终小于结束时间的字段
两个问题: