为什么Python对象可以有由整数表示的属性?
我觉得我可能对Python中的属性有一些基本的误解。考虑以下内容:
>>> class Test:
... pass
...
>>> t = Test()
>>> setattr(t, '0', 0)
>>> t.0
File "<stdin>", line 1
t.0
^
SyntaxError: invalid syntax
>>> getattr(t, '0')
0
>>> setattr(t, 'one', 1)
>>> t.one
1
>>> getattr(t, 'one')
1
为什么Python允许我设置一个属性,但我却不能用点号(.)的方式合法地访问它呢?我明白t.0
没有意义,但同时我也在想,为什么它和t.one
没有什么不同,因为我创建它们的方式是一样的。
2 个回答
2
属性是任何Python对象都可以拥有的一种成员。通常,你会认为Python的语法会规定什么样的属性名称是可以接受的。关于这一点,定义是相当清楚的:
attributeref ::= primary "." identifier
在点号后面跟着的内容必须是一个有效的标识符,这就限制了可以使用的属性名称。暂时不考虑其他Unicode字符,这基本上意味着属性名称不能以数字开头。所以像0
这样的名称就不是有效的标识符,因此t.0
在规范中也不是一个有效的属性引用。
不过,getattr
等函数的工作方式有点不同。它们只要求属性名称是一个字符串。这个字符串会直接传递给内部的PyObject_GetAttr
函数,而这些函数并不需要一个有效的标识符。
所以通过使用getattr
等函数,你实际上可以“欺骗”Python,给对象添加一些在语言规范中不被允许的属性名称。
1
这只是Python语法和语义的一个小特点。任何字符串都可以用作属性名称,但只有标识符(也就是符合命名规则的名称)才能用点号来访问。因此,访问那些不是标识符的属性,唯一的方法就是使用getattr/setattr或者其他一些间接的函数。奇怪的是,这种做法并不意味着任何类型都可以作为属性,只有字符串才有这个特权。