不是有效 python 标识符的属性



通常的属性访问方法要求属性名称是有效的python标识符。

但是属性不一定是有效的python标识符:

>>> class Thing:
...     def __init__(self):
...         setattr(self, '0potato', 123)
...         
>>> t = Thing()
>>> Thing.__getattribute__(t, '0potato')
123
>>> getattr(t, '0potato')
123

当然,t.0potato仍然是SyntaxError,但属性仍然存在:

>>> vars(t)
{'0potato': 123}

这是允许的原因是什么?对于带有空格、空字符串、python保留关键字等的属性,真的有任何有效的用例吗?我认为原因是属性只是对象/命名空间dict中的键,但这毫无意义,因为其他对象是有效的dict键是不允许的:

>>> setattr(t, ('tuple',), 321)
TypeError: attribute name must be string, not 'tuple'

帖子评论中的详细信息完全回答了这个问题,所以我将其作为答案发布:

Guido说:

这是一个功能,您可以使用任何任意字符串使用getattr()和setattr(。然而,这些功能应该(而且确实如此!)拒绝非字符串。

可能的用例包括对常规点式访问隐藏属性,以及使属性与外部数据源相对应(这可能与Python关键字冲突)。因此,争论似乎根本没有充分的理由禁止它

至于禁止非字符串的原因,这似乎是一个合理的限制,可以确保实现的更高性能:

尽管Python的dicts已经有了一些仅限字符串的优化——但一旦出现第一个非键字符串,它们就会动态地适应更通用、稍微慢一点的方法。

因此,为了回答用例问题,从上面的注释中查看Python在引用中的工作原理,我们可以推断出一些可能使这种Python怪癖有用的情况。

  1. 你希望一个对象有一个不能用点符号访问的属性,比如说,保护它不受天真用户的影响。(引用Guido的话:"有些人可能会用这个来隐藏他们不想使用正则属性表示法(x.foo)访问的状态"。当然,他接着说,"但对我来说,这感觉像是滥用了命名空间,还有很多其他的管理这种状态的方法。")
  2. 您希望对象的属性名称与您无法控制的外部数据相对应。因此,您必须能够使用外部数据中出现的任何字符串作为属性名称,即使它与Python保留字匹配或包含嵌入的空格或破折号等

最新更新