例如,此代码是Python:
a = object()
a.b = 3
抛出AttributeError: 'object' object has no attribute 'b'
但是,这段代码:
class c(object): pass
a = c()
a.b = 3
很好。当类x没有该属性时,为什么我可以分配属性b?如何让我的类只定义属性?
答案 0 :(得分:12)
object
类型是用C编写的内置类,不允许您向其添加属性。它已被明确编码以防止它。
在自己的类中获得相同行为的最简单方法是使用__slots__
属性来定义要支持的确切属性的列表。 Python将为这些属性保留空间,不允许任何其他属性。
class c(object):
__slots__ = "foo", "bar", "baz"
a = c()
a.foo = 3 # works
a.b = 3 # AttributeError
当然,这种方法有一些注意事项:你不能腌制这样的对象,而且期望每个对象都具有__dict__
属性的代码会破坏。 “更多Pythonic”的方式是使用另一张海报所示的自定义__setattr__()
。当然,有很多方法可以解决这个问题,并且无法设置__slots__
(除了子类化和将属性添加到子类之外)。
一般来说,这不是你应该在Python中真正想做的事情。如果你的类的用户想要在类的实例上存储一些额外的属性,那么就没有理由不让它们出现,实际上你可能想要的原因很多。
答案 1 :(得分:3)
您可以像这样覆盖__setattr__
魔法的行为。
class C(object):
def __setattr__(self, name, value):
allowed_attrs = ('a', 'b', 'c')
if name not in allowed_attrs:
# raise exception
# or do something else
pass
self.__dict__[name] = value
当然,这只会阻止您设置a.b(点形式)等属性。您仍然可以使用a.__dict__[b]
= value设置属性。在这种情况下,您也应该覆盖__dict__
方法。
答案 2 :(得分:2)
Python通常允许您在任何对象上设置任何属性。这是object
类的行为不同的特殊情况。还有一些在C中实现的模块,其行为类似。
如果希望您的对象的行为如此,那么您可以定义一个__setattr__(self, name, value)
方法,如果您尝试设置一个不在其上的成员,则明确执行raise AttributeError()
“核准清单”(见http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/389916)
答案 3 :(得分:0)
创建object
实例没有任何功能。因此,明确禁用在基本object
类型的实例上设置属性。您必须将其子类化才能创建属性。
提示:如果您希望将简单对象用作存储属性的内容,则可以通过使用lambda
创建匿名函数来实现。作为对象的函数也能够存储属性,因此这是完全合法的:
>>> a = lambda: None
>>> a.b = 3
>>> a.b
3
答案 4 :(得分:-1)
这是因为当你说a.b = 3
时,它会在表示b的变量中创建一个变量。例如,
class a: pass
print a.b
返回AttributeError: class a has no attribute b
但是这段代码,
class a: pass
a.b = 3
print a.b
返回3,因为它将a的b值设置为3。