如何正确重写Python新样式类中的__setattr__和__getattribute__?
我想要重写我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
。
你可以查看关于自定义属性访问的文档了解更多信息。