假设这是我的类(class):
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>", line 1, in <module>
File "<string>", line 10, in __setattr__
AttributeError: A instance has no attribute 'bad_attr'
当然,坚定的开发人员仍然可以通过向 a.__dict__
实例字典添加键来向您的实例添加属性。
另一种选择是利用 __slots__
的副作用;插槽用于节省内存,因为字典比将值直接放入 Python 为每个实例创建的 C 结构中占用更多空间(那时不需要键和动态表)。副作用是在这样的类实例上没有更多属性的地方:
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>", line 1, in <module>
AttributeError: 'A' object has no attribute 'bad_attr'
但请务必阅读文档中列出的有关使用 __slots__
的注意事项。
因为在使用 __slots__
时没有 __dict__
实例属性,这个选项实际上关闭了在实例上设置任意属性的大门。
关于python - 使 Python 类在创建新属性时抛出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25061792/