如何正确重写Python新样式类中的__setattr__和__getattribute__?

51 投票
3 回答
44403 浏览
提问于 2025-04-16 23:29

我想要重写我Python类中的__getattribute____setattr__方法。我的需求很常见:我有一些特殊的名字想要处理,而对于其他的名字我想要默认的行为。对于__getattribute__,我可以通过抛出AttributeError来请求默认行为。但是,在__setattr__中,我该怎么做呢?下面是一个简单的例子,展示了一个有不可变字段"A"、"B"和"C"的类。

class ABCImmutable(SomeSuperclass):
    def __getattribute__(self, name):
        if name in ("A", "B", "C"):
            return "Immutable value of %s" % name
        else:
            # This should trigger the default behavior for any other
            # attribute name.
            raise AttributeError()

    def __setattr__(self, name, value):
        if name in ("A", "B", "C"):
            raise AttributeError("%s is an immutable attribute.")
        else:
            # How do I request the default behavior?
            ???

问号的位置应该填什么呢?在旧式类中,答案显然是self.__dict__[name] = value,但文档显示这对于新式类来说是错误的。

3 个回答

1

下面的代码似乎可以解决这个问题:

class ABCImmutable:
    def __getattribute__(self, name:str):
        if name in ("A", "B", "C"):
            return "Immutable value of %s" % name
        else:
            return super(ABCImmutable, self).__getattribute__(name)

    def __setattr__(self, name:str, value):
        if name in ("A", "B", "C"):
            msg = "%s is an immutable attribute." % name
            # msg = f"{name} is an immutable attribute."
            # msg = "{} is an immutable attribute.".format(name)
            raise AttributeError(msg)
        else:
            super().__setattr__(name, value)
6

你在问的是如何使用SomeSuperclass.__setattr__(self, name, value)这个方法。

53

在Python 2中,你可以这样做:

super(ABCImmutable, self).__setattr__(name, value)

而在Python 3中,你可以这样:

super().__setattr__(name, value)

另外,抛出AttributeError并不是让__getattribute__回到默认行为的方式。要回到默认行为,你应该使用:

return super(ABCImmutable, self).__getattribute__(name)

在Python 2中,或者

return super().__getattribute__(name)

在Python 3中。

抛出AttributeError会跳过默认的处理方式,直接去调用__getattr__,如果没有__getattr__,那么就会在调用的代码中产生一个AttributeError

你可以查看关于自定义属性访问的文档了解更多信息。

撰写回答