我想在类中的属性setter中进行一些验证。必须在对象创建期间设置此属性,然后它必须从外部只读。
我找到了以下解决方案,我想知道是否有更简单或Pythonic的方法来做到这一点。
(我知道通过从外部调用user._username
仍然可以设置此属性,但“我们都同意成年人”等 - 重要的是user.username
不应该有一个二传手)。谢谢你的想法!
class User:
def __init__(self, username):
self._usernname = username
@property
def username(self):
return self.__username
@property
def _username(self):
return self.__username
@_username.setter
def _username(self, value):
if not value or len(value) < 3:
raise ValueError('Invalid username')
self.__username = value
编辑:除了此处的评论之外,还可以在此处找到构造函数中的验证选项:https://mail.python.org/pipermail/python-list/2009-December/562185.html
答案 0 :(得分:0)
您的示例很有趣,因为您都需要只读(这就是为什么您创建只读属性立面username
)和验证(这就是为什么还要使用设置器为内部属性_username
创建一个属性)的原因。
您可以使用pyfields
高效地完成相同操作:
from pyfields import field
class User(object):
username = field(read_only=True,
validators={'should contain more than 2 characters': lambda s: len(s) > 2})
u = User()
u.username = "earthling"
print("Hello %s !\n" % u.username)
print(vars(u))
print()
u.username = "earthling2" # <-- raises error
收益
Hello earthling !
{'_username': 'earthling'}
pyfields.core.ReadOnlyFieldError:
Read-only field '<...>.User.username' has already been initialized on
instance <<...>.User object at 0x0000022895908EF0> and cannot be modified anymore.
它基本上与您手动执行的操作类似,不同之处在于它依赖于描述符而不是属性(descriptor是python在属性中使用的底层协议)。而且,它仅依赖于一个“嵌套”级别:内部属性_username
是一个普通的旧属性,如上面ekhumoro
的注释所建议的那样。
有关详细信息,请参见pyfields
documentation。