对int literals的属性访问

时间:2014-10-08 11:23:00

标签: python parsing grammar lexical-analysis

>>> 1 .__hash__()
1
>>> 1.__hash__()
  File "<stdin>", line 1
    1.__hash__()
             ^
SyntaxError: invalid syntax

之前已经介绍过第二个例子不起作用,因为int literal实际上被解析为float。

我的问题是,为什么没有 python将这解析为int上的属性访问,当解释为float是语法错误? lexical analysis上的文档部分似乎暗示只有当其他解释含糊不清时才需要空格,但也许我读错了这部分。

预感似乎lexer是贪婪的(试图获取最大的令牌),但我没有这个说法的来源。

3 个答案:

答案 0 :(得分:3)

词法分析器非常简单,不会回溯。语言解析器通常分为lexing阶段和解析阶段,或词法分析器和解析器。词法分析器将字符流分解为标记,然后解析器从标记中确定程序结构。词法分析器会看到四个标记:1.__hash__():float,identifier,open-paren,close-paren。解析器无法理解这些令牌,但这并不意味着词法分析器会尝试以不同方式对字符进行修饰。

答案 1 :(得分:3)

这只是一个定义问题;对于语言,语法可以胜任。

Attribute references的定义范围远远超过floating point literals。因此,从语法层面来看,解析器必须将1.识别为浮点文字而不是属性引用。

当然,解析器本身可以在到达_时回溯,并试图弄清楚它的不是浮点文字而是属性引用。但是,由于CPython的解析器是LL(1) parser回溯不是一个选项。因此,语法必须进行大量更改以允许解析器识别这一点(尽管我现在还不确定它是否可能使用LL(1)解析器)。我们还可以改变Python的解析器别的东西,也许一个不走回头路,但这样做不仅是一个非常艰巨的任务(它也需要改变语法),但会增加解析过程的复杂很多(与这可能会降低速度。)

所以可能它是可能的,但它需要对语言规范进行重大更改。仅这一点就会有问题。它还会破坏利用这种早期浮点识别的现有代码,例如: 1.if True else 0

答案 2 :(得分:2)

仔细阅读,它说

  

只有当两个令牌的串联被解释为不同的令牌时才需要空格(例如,ab是一个令牌,但b是两个令牌)。

1.__hash__()被标记为:

import io, tokenize
for token in tokenize.tokenize(io.BytesIO(b"1.__hash__()").read):
    print(token.string)

#>>> utf-8
#>>> 1.
#>>> __hash__
#>>> (
#>>> )
#>>>

Python的词法分析器会选择一个标记which comprises the longest possible string that forms a legal token, when read from left to right;解析后,没有两个令牌应该能够组合成一个有效的令牌。逻辑与in your other question非常相似。

混淆似乎并没有将标记化步骤视为一个完全不同的步骤。如果语法允许分割标记仅仅是为了让解析器满意那么你肯定会期待

_ or1.

标记为

_
or
1.

但没有这样的规则,所以它标记为

_
or1
.