Python:类能否禁止客户端设置新属性?

15 投票
1 回答
3480 浏览
提问于 2025-04-16 00:33

我刚花了太多时间在一个像下面这样的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__ 而不是直接赋值来实现。(如果你想禁止在一个上设置属性,而只允许在它的实例上设置,你需要定义一个自定义的元类,并实现类似的特殊方法)。

撰写回答