Python getter方法中的验证

Python getter方法中的验证,python,properties,getter,setter,Python,Properties,Getter,Setter,通常,当我在类中使用属性并且同时使用getter和setter方法时,我在setter中执行所有验证检查 另一方面,如果我想限制最终用户更改属性的值,但仍然需要执行验证,我该怎么办?我只是把支票放进了getter,虽然我不确定它是否真的属于那里 class Foo: def __init__(self, value): self.__value = value @property def value(self): if not isins

通常,当我在类中使用属性并且同时使用getter和setter方法时,我在setter中执行所有验证检查

另一方面,如果我想限制最终用户更改属性的值,但仍然需要执行验证,我该怎么办?我只是把支票放进了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
我想,我也可以在
\uuuu init\uuuu
中进行验证,但这也很难看

编辑:

>>> 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
>a=Foo('bar'))
回溯(最近一次呼叫最后一次):
文件“C:\python\block\u model\u variable\u imputer\venv\u fixed\lib\site packages\IPython\core\interactiveshell.py”,第3437行,运行代码
exec(代码对象、self.user\u全局、self.user\n)
文件“”,第1行,在
a=Foo('bar'))
文件“”,第3行,在_init中__
self.u val=val
文件“”,第12行,在
提升值错误()
数值误差
我个人认为

Foo类:
定义初始值(自身,值):
如果不是isinstance(值,int):
raise TypeError(f'需要一个整数,得到{type(value)}'))
其他:
自我价值=价值
@财产
def值(自身):
返回self.\u值
注意,我使用了
TypeError
而不是
ValueError
,因为这是这里更合适的异常类型;)

这解决了这两个问题

a) 在访问属性之前,不会进行任何验证;b)每次访问属性时都会执行验证,这可能会导致成本高昂

也不会像在第二个代码段中那样引入额外的helper变量。让setter和getter(用于
\uu val
)专门用于内部使用对我来说是一种不好的做法

如果第二个代码段的目标是为了可读性而将检查逻辑移出
\uuuu init\uuuu
,则可以执行以下操作

Foo类:
定义初始值(自身,值):
自我检查值=自我检查值输入(值)
定义检查值输入(值):
如果不是isinstance(值,int):
raise TypeError(f'需要一个整数,得到{type(value)}'))
其他:
返回值
@财产
def值(自身):
返回self.\u值
这还有一个好处,即如果在某个时候确实需要以其他速度检查输入,例如,如果您决定亲自为

重新添加setter,则可以重用
\u check\u value\u input

Foo类:
定义初始值(自身,值):
如果不是isinstance(值,int):
raise TypeError(f'需要一个整数,得到{type(value)}'))
其他:
自我价值=价值
@财产
def值(自身):
返回self.\u值
注意,我使用了
TypeError
而不是
ValueError
,因为这是这里更合适的异常类型;)

这解决了这两个问题

a) 在访问属性之前,不会进行任何验证;b)每次访问属性时都会执行验证,这可能会导致成本高昂

也不会像在第二个代码段中那样引入额外的helper变量。让setter和getter(用于
\uu val
)专门用于内部使用对我来说是一种不好的做法

如果第二个代码段的目标是为了可读性而将检查逻辑移出
\uuuu init\uuuu
,则可以执行以下操作

Foo类:
定义初始值(自身,值):
自我检查值=自我检查值输入(值)
定义检查值输入(值):
如果不是isinstance(值,int):
raise TypeError(f'需要一个整数,得到{type(value)}'))
其他:
返回值
@财产
def值(自身):
返回self.\u值

这还有一个好处,即如果在某些时候确实需要以其他速度检查输入,例如,如果您决定为

重新添加setter,那么您可以重用
\u check\u value\u input
,哦,是的,这更有意义。我知道我把事情搞得太复杂了。哦,是的,这更有意义。我知道我把事情搞得太复杂了。