getter 方法中的验证
Validation in a getter method
通常,当我在 类 中使用属性并同时使用 getter 和 setter 方法时,我会在 setter.[=15 中进行所有验证检查=]
另一方面,如果我想限制最终用户更改 属性 的值但仍需要执行验证,我该怎么办?我只是将支票放入 getter,尽管我不确定它是否真的属于那里。
class Foo:
def __init__(self, value):
self.__value = value
@property
def value(self):
if not isinstance(value, int):
raise ValueError(f'Expecting an integer, got {type(value)}.')
else:
return self.__value
这工作正常,但问题是 a) 在访问 属性 之前不进行验证,并且 b) 每次访问 属性 时都执行验证,这可能会变得昂贵.
所以我制作了以下版本。它解决了上述问题,但看起来和感觉都不对。有没有更好的方法来做到这一点:
class Foo:
def __init__(self, val):
self.__val = val
@property
def __val(self):
return self.__tmp
@__val.setter
def __val(self, value):
if not isinstance(value, int):
raise ValueError()
else:
self.__tmp = value
@property
def value(self):
return self.__val
我想,我也可以在 __init__
中进行验证,但这也很难看。
编辑:
>>> a = Foo('bar')
Traceback (most recent call last):
File "C:\python\block_model_variable_imputer\venv_fixed\lib\site-packages\IPython\core\interactiveshell.py", line 3437, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-8-637c10c15d73>", line 1, in <module>
a = Foo('bar')
File "<ipython-input-7-f7d16143eb85>", line 3, in __init__
self.__val = val
File "<ipython-input-7-f7d16143eb85>", line 12, in __val
raise ValueError()
ValueError
就我个人而言,我会选择
class Foo:
def __init__(self, value):
if not isinstance(value, int):
raise TypeError(f'Expecting an integer, got {type(value)}.')
else:
self.__value = value
@property
def value(self):
return self.__value
请注意,我使用的是 TypeError
而不是 ValueError
,因为这是更合适的异常类型;)
这解决了两个问题
a) no validation is done until the property is accessed and b) validation is performed every time a property is accessed, which can get expensive.
并且也没有像第二个代码段那样引入额外的辅助变量。让 setters 和吸气剂(对于 __val
)专门供内部使用对我来说似乎是不好的做法……
如果您的第二个代码段的目标是将检查逻辑移出 __init__
以提高可读性,您可以执行类似
的操作
class Foo:
def __init__(self, value):
self.__value = self._check_value_input(value)
def _check_value_input(value):
if not isinstance(value, int):
raise TypeError(f'Expecting an integer, got {type(value)}.')
else:
return value
@property
def value(self):
return self.__value
这还有一个好处,即如果您确实需要以其他速度检查输入,则可以重复使用 _check_value_input
,例如如果您决定为 value
.
重新添加 setter
通常,当我在 类 中使用属性并同时使用 getter 和 setter 方法时,我会在 setter.[=15 中进行所有验证检查=]
另一方面,如果我想限制最终用户更改 属性 的值但仍需要执行验证,我该怎么办?我只是将支票放入 getter,尽管我不确定它是否真的属于那里。
class Foo:
def __init__(self, value):
self.__value = value
@property
def value(self):
if not isinstance(value, int):
raise ValueError(f'Expecting an integer, got {type(value)}.')
else:
return self.__value
这工作正常,但问题是 a) 在访问 属性 之前不进行验证,并且 b) 每次访问 属性 时都执行验证,这可能会变得昂贵.
所以我制作了以下版本。它解决了上述问题,但看起来和感觉都不对。有没有更好的方法来做到这一点:
class Foo:
def __init__(self, val):
self.__val = val
@property
def __val(self):
return self.__tmp
@__val.setter
def __val(self, value):
if not isinstance(value, int):
raise ValueError()
else:
self.__tmp = value
@property
def value(self):
return self.__val
我想,我也可以在 __init__
中进行验证,但这也很难看。
编辑:
>>> a = Foo('bar')
Traceback (most recent call last):
File "C:\python\block_model_variable_imputer\venv_fixed\lib\site-packages\IPython\core\interactiveshell.py", line 3437, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-8-637c10c15d73>", line 1, in <module>
a = Foo('bar')
File "<ipython-input-7-f7d16143eb85>", line 3, in __init__
self.__val = val
File "<ipython-input-7-f7d16143eb85>", line 12, in __val
raise ValueError()
ValueError
就我个人而言,我会选择
class Foo:
def __init__(self, value):
if not isinstance(value, int):
raise TypeError(f'Expecting an integer, got {type(value)}.')
else:
self.__value = value
@property
def value(self):
return self.__value
请注意,我使用的是 TypeError
而不是 ValueError
,因为这是更合适的异常类型;)
这解决了两个问题
a) no validation is done until the property is accessed and b) validation is performed every time a property is accessed, which can get expensive.
并且也没有像第二个代码段那样引入额外的辅助变量。让 setters 和吸气剂(对于 __val
)专门供内部使用对我来说似乎是不好的做法……
如果您的第二个代码段的目标是将检查逻辑移出 __init__
以提高可读性,您可以执行类似
class Foo:
def __init__(self, value):
self.__value = self._check_value_input(value)
def _check_value_input(value):
if not isinstance(value, int):
raise TypeError(f'Expecting an integer, got {type(value)}.')
else:
return value
@property
def value(self):
return self.__value
这还有一个好处,即如果您确实需要以其他速度检查输入,则可以重复使用 _check_value_input
,例如如果您决定为 value
.