【问题标题】:Why can't attribute names be Python keywords?为什么属性名称不能是 Python 关键字?
【发布时间】:2012-04-02 13:28:02
【问题描述】:

在 Python 中(至少在 CPython 2.7.2 实现中)对属性访问的语法有限制:

>>> class C(object): pass
>>> o = C()
>>> o.x = 123  # Works
>>> o.if = 123
    o.if = 123
       ^
SyntaxError: invalid syntax

我的问题有两个:

  1. 禁止使用 Python 关键字属性名称(如o.if = 123)是否有根本原因?
  2. 是否/在哪里记录了上述对属性名称的限制?

在我的一个程序中执行o.class = … 是有意义的,但我对无法执行此操作有点失望(o.class_ 可以,但看起来并不简单)。

PS:问题显然是ifclass是Python关键字。问题是为什么禁止使用关键字作为属性名称(我没有看到表达式o.class = 123 有任何歧义),以及这是否记录在案。 p>

【问题讨论】:

  • 因为当关键字总是关键字而不是上下文时,解析器会更简单。所以代码甚至没有到达属性访问的地步,它只是解析级别的语法错误(因为if 是语法的一部分,它从未出现在这个地方)。大多数语言都是一样的,语言语法就是它的文档。
  • 另外,cls 通常用于包含对类的引用的名称。
  • 即使您有一个可以将关键字与变量/函数名称区分开来的解析器,也不能保证在极端情况下一个可能会影响另一个。如果你直接禁止使用几十个名字,那么保持理智会容易得多。
  • @CatPlusPlus:很好的答案。只是解析器效率的设计决策。 Python 成语是if_while_exec_ 等,用于关键字名称冲突。 _foo 被认为是受保护属性的模式
  • @CatPlusPlus:回答,不评论。您实际上已经回答了它,而目前的答案根本没有回答。

标签: python attributes syntax-error


【解决方案1】:

因为当关键字始终是关键字而不是上下文时,解析器更简单(例如,if 在语句级别是关键字,但在表达式中只是标识符 - 对于if,它会加倍困难,因为的X if C else Yfor 用于列表推导和生成器表达式)。

所以代码甚至没有到达属性访问的地步,它只是被解析器拒绝,就像不正确的缩进一样(这就是为什么它是 SyntaxError,而不是 AttributeError 或其他东西)。它不区分您使用if 作为属性名、变量名、函数名还是类型名。它永远不可能是标识符,因为解析器总是为其分配“关键字”标签,并使其成为与标识符不同的标记。

在大多数语言中都是一样的,语言语法(+ 词法分析器规范)就是它的文档。 Language spec mentions it explicitly。它在 Python 3 中也没有改变。

此外,仅仅因为您可以使用setattr__dict__ 来创建具有保留名称的属性,并不意味着您应该。不要强迫自己/API 用户使用getattr 而不是自然属性访问。 getattr 应保留用于需要访问变量属性名称时。

【讨论】:

  • 这就是老师在编译器课程中告诉我们的方式。这就是编译器的经典构建方式。令牌被拆分,分类,然后分析器是否对它们有意义。每个像 + 或 : 这样的特殊符号都有自己的(单一的)类别,以及每个保留字(“if”、“or”、“class”、“def”等)。每个其他单词都属于一个特殊的类别:标识符。由于“if”不是标识符,它不能命名属性,就这么简单。我并不是说不可能以其他方式构建编译器/代码分析器,这就是这些天的工作方式......
  • @Ivella:非常相关的评论 +1。
  • @CatPlusPlus:同意,关于getattr__dict__。我只是提到这些是因为它们表明属性名称可以是关键字,即使通常的 object.attribute 语法禁止它。
  • @EOL:这又归结为语法。 'if' 始终是字符串文字,而不是关键字。而且由于属性保存在字典中,所以任何字符串都可以。
【解决方案2】:

因为if 是关键字。 o.whileo.for 也有类似的问题:

pax> python
>>> class C(object): pass
... 

>>> o = C()

>>> o.not_a_keyword = 123

>>> o.if = 123
  File "<stdin>", line 1
    o.if = 123
       ^
SyntaxError: invalid syntax

>>> o.while = 123
  File "<stdin>", line 1
    o.while = 123
          ^
SyntaxError: invalid syntax

>>> o.for = 123
  File "<stdin>", line 1
    o.for = 123
        ^
SyntaxError: invalid syntax

Python中的其他关键字可以通过:

>>> import keyword
>>> keyword.kwlist
['and', 'as', 'assert', 'break', 'class', 'continue', 'def',
 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for',
 'from', 'global', 'if', 'import', 'in', 'is', 'lambda',
 'not', 'or', 'pass', 'print', 'raise', 'return', 'try',
 'while', 'with', 'yield']

您应该在 Python 中通常使用关键字作为变量名。

我建议选择一个更具描述性的名称,例如 iface 如果它是一个接口,或者 infld 用于输入字段等等。

至于您对 why 关键字的问题进行编辑,如果词法元素是上下文无关的,它会大大简化解析器。必须在某些地方将词法标记 if 视为关键字,而在其他地方将标识符视为标识符会引入复杂性,如果您更明智地选择标识符,则实际上不需要。

例如 C++ 语句:

long int int = char[new - int];

可以(有一点困难)根据这些词法元素出现的位置(以及它们两侧存在的内容)使用复杂的解析器进行评估。但是,(至少部分地)为了简单(和可读性),没有这样做。

【讨论】:

  • 是的,确实如此。我更新了问题的标题,以明确问题是为什么关键字将被禁止作为属性名称。其实在o.class = 123中,很明显class应该是一个属性名;但是,这不是有效的 (C)Python;一定有充分的理由说明这对 CPython 解释器来说不应该是显而易见的:这些原因是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
  • 2013-09-25
相关资源
最近更新 更多