>>> 1 .__hash__()
1
>>> 1.__hash__()
File "<stdin>", line 1
1.__hash__()
^
SyntaxError: invalid syntax
之前已经介绍过第二个例子不起作用,因为int literal实际上被解析为float。
我的问题是,为什么没有 python将这解析为int上的属性访问,当解释为float是语法错误? lexical analysis上的文档部分似乎暗示只有当其他解释含糊不清时才需要空格,但也许我读错了这部分。
预感似乎lexer是贪婪的(试图获取最大的令牌),但我没有这个说法的来源。
答案 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
.