setattr 接受无效标识符

sam*_*pyt 2 python

这就是我的意思:

>>> class Foo:
        pass

>>> foo = Foo()
>>> setattr(foo, "@%#$%", 10)
>>> foo.@%#$%
SyntaxError: invalid syntax
>>> getattr(foo, "@%#$%")
10
>>> foo.__dict__
{'@%#$%': 10}
Run Code Online (Sandbox Code Playgroud)

我查了一下,它在 python 2 的问题跟踪器上出现了两次:

https://bugs.python.org/issue14029

https://bugs.python.org/issue25205

一次是 Python 3:

https://bugs.python.org/issue35105

他们坚持认为这不是错误。然而,这种行为显然不是故意的。它没有记录在任何版本中。对此有何解释?这似乎是很容易被忽略的东西,但这感觉就像把它扫到地毯下一样。那么,setattr的行为背后是否有任何原因,或者它只是 python 的一种良性特质?

pax*_*blo 5

一个错误的东西当它不出现这种情况应该发生的,也就是说,当有禁止其通信的一些方法。如果没有文档说明这不应该发生,那么(最坏的情况)这是一种特质,而不是错误。

Python 文档中似乎没有任何内容禁止不能与点表示法一起使用的属性名称(毕竟,这只是语法糖),例如foo.@%#$%. 唯一提到的是它们等效的示例,特别是:

例如,setattr(x, 'foobar', 123)相当于x.foobar = 123

唯一的限制似乎是类本身是否允许它:

如果对象允许,该函数将值分配给属性。


在更正式的意义上,点符号在此处指定:

6.3.1. 属性引用

属性引用是一个primary,后跟一个句点和一个名称:attributeref ::= primary "." identifier

primary结果必须为类型支持属性引用,其中大部分物体做的一个目的。然后要求此对象生成名称为 的属性identifier。可以通过覆盖该__getattr__()方法来定制此生产。

请注意,identifier在该语法中,根据此处,它具有超出实际属性名称的限制,并且PEP 3131更详细地了解了允许的内容(正是 PEP 将标识符移到了非 ASCII 世界)。

由于标识符的限制比字符串中允许的限制更严格,因此getattr/setattr属性名称可以是点符号中允许的名称的超集是有道理的。