Python:类能否禁止客户端设置新属性?
我刚花了太多时间在一个像下面这样的bug上:
>>> class Odp():
def __init__(self):
self.foo = "bar"
>>> o = Odp()
>>> o.raw_foo = 3 # oops - meant o.foo
我有一个类,里面有一个属性。我试着去设置这个属性,但发现没有任何效果。然后我回去查看原来的类定义,发现这个属性的名字稍微有点不同。所以,我实际上是在创建/设置一个新的属性,而不是我想要的那个。
首先,这不就是静态类型语言应该防止的错误吗?在这种情况下,动态类型有什么好处呢?
其次,有没有办法在定义Odp
的时候就禁止这种情况,从而让我省去麻烦呢?
1 个回答
22
你可以实现一个 __setattr__
方法来达到这个目的——这比 __slots__
要强大得多,因为 __slots__
常常被误用(比如,当类被继承时,__slots__
会自动“消失”,而 __setattr__
除非被明确重写,否则会一直存在)。
def __setattr__(self, name, value):
if hasattr(self, name):
object.__setattr__(self, name, value)
else:
raise TypeError('Cannot set name %r on object of type %s' % (
name, self.__class__.__name__))
你需要确保 hasattr
对于你想要设置的属性名是成功的,比如通过在类层面上设置属性,或者在你的 __init__
方法中使用 object.__setattr__
而不是直接赋值来实现。(如果你想禁止在一个类上设置属性,而只允许在它的实例上设置,你需要定义一个自定义的元类,并实现类似的特殊方法)。