这个问题在这里已经有了答案:
Why doesn't 2.__add__(3) work in Python?
(2 个回答)
7年前关闭。
我在玩 Python 解释器(Python 3.2.3)并尝试了以下操作:
>>> dir(1)
这给了我 int 对象的所有属性和方法。接下来我尝试:
>>> 1.__class__
然而,这引发了一个异常:
File "<stdin>", line 1
1.__class__
^
SyntaxError: invalid syntax
当我用浮点数尝试相同时,我得到了我的预期:
>>> 2.0.__class__
<class 'float'>
为什么要
int
和 float
文字的行为不同?
最佳答案
这可能是所使用的解析算法的结果。一个简单的心智模型是分词器尝试匹配 全部 存在的 token 模式,并识别 最长 匹配它找到。在较低级别上,分词器逐个字符地工作,并且仅根据当前状态和输入字符做出决定——不应有任何回溯或重新读取输入。
加入具有公共(public)前缀的模式后——在本例中,是 int
的模式文字和 float
模式的组成部分文字 – 在分词器中发生的事情是:
1
,并进入指示“正在读取 float
或 int
文字”.
,并进入状态“阅读 float
文字”_
,不能是 float
的一部分文字。解析器发出 1.
作为 float
文字标记。 _
开始继续解析,并最终发出 __class__
作为标识符 token 。 Aside: This tokenizing approach is also the reason why common languages have the syntax restrictions they have. E.g. identifiers contain letters, digits, and underscores, but cannot start with a digit. If that was allowed,
123abc
could be intended as either an identifier, or the integer123
followed by the identifierabc
.A lex-like tokenizer would recognize this as the former since it leads to the longest single token, but nobody likes having to keep details like this in their head when trying to read code. Or when trying to write and debug the tokenizer for that matter.
然后解析器尝试处理 token 流:
<FloatLiteral: '1.'> <Identifier: '__class__'>
在 Python 中,直接后跟标识符的文字——在标记之间没有运算符——是没有意义的,所以解析器会保释。这也意味着Python会提示
123abc
的原因。语法无效不是分词器错误“字符 a
在整数文字中无效”,而是解析器错误“标识符 abc
不能直接跟在整数文字 123
后面”分词器无法识别
1
的原因作为 int
文字是使它 的字符离开 float
-或- int
状态决定了它刚刚读取的内容。如果是 .
,这是 float
的开始字面意思,之后可能会继续。如果是别的东西,那就是一个完整的int
文字标记。分词器不可能“返回”并将先前的输入重新读取为其他内容。事实上,tokenizer 的级别太低,无法关心“属性访问”是什么并处理这种歧义。
现在,您的第二个示例是有效的,因为标记器知道
float
文字只能有一个 .
在里面。更准确地说:第一个.
使其从 float
过渡-或- int
状态到 float
状态。在这种状态下,它只需要数字(或 E
用于科学/工程符号, j
用于复数......)继续 float
文字。第一个不是数字等的字符(即 .
)绝对不再是 float
的一部分文字和分词器可以发出完成的标记。因此,您的第二个示例的 token 流将是:<FloatLiteral: '1.'> <Operator: '.'> <Identifier: '__class__'>
当然,解析器随后将其识别为有效的 Python。现在我们也足够了解为什么建议的解决方法会有所帮助。在 Python 中,用空格分隔标记是 可选 – 不像,比如说,在 Lisp 中。相反,空格 是否单独的 token 。 (也就是说,除了
string
文字之外没有任何标记可能包含空格,它只是在标记之间跳过。)所以代码:1 .__class__
总是被标记为
<IntLiteral: '1'> <Operator: '.'> <Identifier: '__class__'>
并且由于右括号不能出现在
int
中字面意思,这个:(1).__class__
读作如下:
<Operator: '('> <IntLiteral: '1'> <Operator: ')'> <Operator: '.'> <Identifier: '__class__'>
以上暗示,有趣的是,以下内容也是有效的:
1..__class__ # => <type 'float'>
float
的小数部分文字是可选的,第二个 .
read 将使前面的输入被识别为一个。
关于python - 获取整数和 float 的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20269435/