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