我有一个通过 @property 装饰器实现属性的类,如下所示
class num(object):
def __init__(self, value):
self.val = value
@property
def val(self):
return self._val
@val.setter
def val(self, value):
validation(self, (int, float), value, 0.0)
当要设置属性值时,应该对其进行验证。
def validation(obj, types, value, default):
"""Checks if the input provided for the attribute is valid."""
try:
if not isinstance(value, types):
obj._val = default
raise TypeError
if value < 0:
obj._val = default
raise ValueError
else:
obj._val = float(value)
except ValueError as e:
print("Should be a positive number. Value set at ", default)
except TypeError:
print("Should be a number. Value set at ", default)
此代码适用于这种特殊情况,我只有一个先验已知属性 val。我想让函数 validation 更通用,以便能够重用于其他属性(例如任意索引)。我可以看到我的问题出在 obj._val 中,我在那里破坏了封装。
我想一种可能的解决方案是通过使用链接到属性 setter 的方法装饰器,或者可能将额外的参数传递给 validation 以了解必须验证哪个属性。或者也许是使用完全不同的方法。
提前致谢!
请您参考如下方法:
让您的验证器仅验证。如果值无效,让它引发异常,并且至多对整数进行float转换。您的验证器对数字过于具体,因此请重命名它(并对其他类型使用其他验证器):
def is_positive_number(value):
"""Checks if the input provided is an actual number, returns a float."""
if not isinstance(value, types):
raise TypeError('Not a number')
if value < 0:
raise ValueError('Must be a positive number')
return float(value)
将设置属性留给setter;它也可以决定默认值:
@val.setter
def val(self, value):
self._val = 0.0 # default, in case validation fails
self._val = validation(value)
现在验证器不再与特定属性紧密耦合。其他更复杂的验证器可以根据需要传递更多上下文。
请注意,错误处理(捕获验证异常并打印消息)实际上应该发生在属性之外。在验证器内部打印会使您的代码与特定的交互模式过于紧密地耦合在一起;例如,您现在不能将此代码用于 Web 界面或 GUI。
