我有些偶然地发现,您可以使用
setattr
为对象设置“非法”属性。所谓“非法”,是指无法使用传统的 .
操作符引用中的__getattr__
接口检索名称的属性。它们只能通过 getattr
方法检索。
对我来说,这似乎相当惊人,我想知道是否有原因,或者是否只是被忽视了等等。由于存在用于检索属性的运算符,以及 setattribute
接口的标准实现,我期望它只允许实际上可以正常检索的属性名称。如果您有一些奇怪的原因想要具有无效名称的属性,则必须为其自己实现接口。
这种行为让我感到惊讶,难道只有我一个人吗?
class Foo:
"stores attrs"
foo = Foo()
setattr(foo, "bar.baz", "this can't be reached")
dir(foo)
这个方法返回的结果既奇怪又有点误导性:[...'__weakref__', 'bar.baz']
如果我想以“标准”方式访问foo.bar.baz,我是无法实现的。不能检索到它是合理的,但能够设置它是令人惊讶的。
foo.bar.baz
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'bar'
假设你必须使用setattr
设置变量,那么就默认你将通过getattr
来引用它吗?因为在运行时,这并不总是正确的,尤其是在Python的交互式解释器、反射等方面。这仍然似乎非常奇怪,为什么默认情况下会允许这种情况。
编辑:以下是setattr默认实现的(非常粗略)示例:
import re
class Safe:
"stores attrs"
def __setattr__(self, attr, value):
if not re.match(r"^\w[\w\d\-]+$", attr):
raise AttributeError("Invalid characters in attribute name")
else:
super().__setattr__(attr, value)
这将不允许我在属性名称中使用无效字符。显然,super()
不能用于基础 Object 类,但这只是一个例子。
foo.__dict__['bar.baz']
... - Charles D Pantogagetattr
。它适用于没有__dict__
的对象,例如。这样的对象很少见(因为通常不鼓励创建它们),但它们确实存在,并且对某些目的非常有用。 - mgilson