使Python类在创建新属性时抛出错误
让我们说这是我的班级:
class A: def __init__(self): self.good_attr = None self.really_good_attr = None self.another_good_attr = None 然后调用者可以设置这些变量的值: a = A() a.good_attr = 'a value' a.really_good_attr = 'better value' a.another_good_attr = 'a good value' 但他们也可以添加新属性: a.goood_value = 'evil' 这对我的用例来说是不可取的.我的对象被用于将一些值传递给一组方法. (基本上,这个对象替换了一些方法上的一长串共享参数,以避免重复,并清楚地区分共享内容和不同内容.)如果调用者拼写错误属性名称,那么该属性将被忽略,导致意外和令人困惑,可能很难弄清楚行为.最好快速失败,通知调用者他们使用了将被忽略的属性名称.所以类似于下面的内容是我们在使用对象上尚不存在的属性名称时所希望的行为: >>> a.goood_value = 'evil' Traceback (most recent call last): File "<stdin>",line 1,in <module> AttributeError: A instance has no attribute 'goood_value' 我怎样才能做到这一点? 我还要注意,我完全清楚调用者可以创建一个新类并做任何他们想做的事情,完全绕过它.但是,这将是不受支持的行为.制作我提供的对象只是创建一个快速失败的骨头检查,以便为那些利用我提供的对象(包括我自己)的人节省打字错误的时间,而不是让他们抓住头脑,想知道为什么事情以意想不到的方式表现. 解决方法
您可以使用__setattr__方法挂钩属性设置.所有属性设置都会调用此方法,因此考虑到它也将被称为“正确”属性:
class A(object): good_attr = None really_good_attr = None another_good_attr = None def __setattr__(self,name,value): if not hasattr(self,name): raise AttributeError( '{} instance has no attribute {!r}'.format( type(self).__name__,name)) super(A,self).__setattr__(name,value) 因为在类上定义了good_attr等,所以hasattr()调用为这些属性返回True,并且不会引发异常.您也可以在__init__中设置相同的属性,但必须在类上定义属性才能使hasattr()起作用. 另一种方法是创建一个可以测试的白名单. 演示: >>> a = A() >>> a.good_attr = 'foo' >>> a.bad_attr = 'foo' Traceback (most recent call last): File "<stdin>",in <module> File "<string>",line 10,in __setattr__ AttributeError: A instance has no attribute 'bad_attr' 当然,确定的开发人员仍然可以通过向.__ dict__实例字典添加键来为您的实例添加属性. 另一种选择是使用 class A(object): __slots__ = ('good_attr','really_good_attr','another_good_attr') def __init__(self): self.good_attr = None self.really_good_attr = None self.another_good_attr = None 然后错误消息如下所示: >>> a = A() >>> a.good_attr = 'foo' >>> a.bad_attr = 'foo' Traceback (most recent call last): File "<stdin>",in <module> AttributeError: 'A' object has no attribute 'bad_attr' 但请阅读文档中列出的使用__slots__的警告. 因为在使用__slots__时没有__dict__实例属性,所以此选项实际上关闭了在实例上设置任意属性的大门. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |