python - 为什么 Python 返回 [15] for [0xfor x in (1, 2, 3)]?
问题描述
运行以下行时:
>>> [0xfor x in (1, 2, 3)]
我希望 Python 返回一个错误。
相反,REPL 返回:
[15]
可能是什么原因?
解决方案
TL;博士
Python 将表达式读取为[0xf or (x in (1, 2, 3))]
,因为:
NameError
由于短路评估,它永远不会引发- 如果留给or
运算符的表达式是一个真实值,Python 将永远不会尝试评估它的右侧。
解析十六进制数
首先,我们要了解 Python 是如何读取十六进制数的。
在tokenizer.c的巨大tok_get
功能上,我们:
- 找到第一个
0x
。 - 只要它们在 0-f 范围内,就继续阅读下一个字符。
解析后的标记0xf
(因为“o”不在 0-f 范围内)最终将被传递给 PEG 解析器,后者会将其转换为十进制值15
(参见附录 A)。
我们仍然需要解析其余的代码,or x in (1, 2, 3)]
,它与以下代码一样:
[15 or x in (1, 2, 3)]
运算符优先级
因为in
具有比更高的运算符优先级or
,我们可能希望x in (1, 2, 3)
首先评估。
这是一个麻烦的情况,因为x
不存在并且会引发NameError
.
or
懒惰
幸运的是,Python像惰性运算符一样支持短路求值or
:如果左操作数等价于True
,Python 不会费心求值右操作数。
我们可以使用ast
模块看到它:
parsed = ast.parse('0xfor x in (1, 2, 3)', mode='eval')
ast.dump(parsed)
输出:
Expression(
body=BoolOp(
op=Or(),
values=[
Constant(value=15), # <-- Truthy value, so the next operand won't be evaluated.
Compare(
left=Name(id='x', ctx=Load()),
ops=[In()],
comparators=[
Tuple(elts=[Constant(value=1), Constant(value=2), Constant(value=3)], ctx=Load())
]
)
]
)
)
所以最终表达式等于[15]
。
附录 A:PEG 解析器
在pegen.c的parsenumber_raw
函数中,我们可以找到 Python 如何处理前导零:
if (s[0] == '0') {
x = (long)PyOS_strtoul(s, (char **)&end, 0);
if (x < 0 && errno == 0) {
return PyLong_FromString(s, (char **)0, 0);
}
}
PyOS_strtoul
在Python/mystrtoul.c
.
在 mystrtoul.c 中,解析器查看0x
. 如果它是一个十六进制字符,Python 将数字的基数设置为 16:
if (*str == 'x' || *str == 'X') {
/* there must be at least one digit after 0x */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
if (ptr)
*ptr = (char *)str;
return 0;
}
++str;
base = 16;
} ...
然后,只要字符在 0-f 范围内,它就会解析其余的数字:
while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
if (ovlimit > 0) /* no overflow check required */
result = result * base + c;
...
++str;
--ovlimit;
}
最终,它将指针设置为指向被扫描的最后一个字符 - 这是最后一个十六进制字符之后的一个字符:
if (ptr)
*ptr = (char *)str;
谢谢
- 来自 reddit 的CSI_Tech_Dept向我介绍了 tokenizer.c 文件中的正确部分。
- 原始推文。
推荐阅读
- c# - NLog - 2 个独立的日志文件 - 如何写入其中一个
- automation - 通过 salesforce API 更改“潜在客户所有者”的流程是什么?
- react-native - 检查第一个孩子是否在本机测试库中不呈现任何内容
- xamarin.forms - 与 SfChart 属性的数据绑定应该与 StaticResource 中的元素一起使用吗?
- android - Spinner 选择时不显示数据,最近也显示微调器数据
- c# - 如何区分 NumericUpDown 控件编辑框和箭头按钮的鼠标事件
- r - 最大化循环/应用功能的速度
- conda - `conda list` 输出的“Channel”列中的“pypi”是什么意思?
- javascript - 转到下一页时表格行消失
- python - Python函数默认参数随机值