当前位置: 首页 > 知识库问答 >
问题:

为什么Python为[0xfor x in(1,2,3)]返回[15]?

冯玮
2023-03-14

运行以下行时:

>>> [0xfor x in (1, 2, 3)]

我以为Python会返回一个错误。

相反,REPL返回:

[15]

原因可能是什么?

共有1个答案

东方吕恭
2023-03-14

Python将表达式读取为[0xF或((1,2,3))],因为:

  1. Python标记器。
  2. 运算符优先级。

由于短路求值,它从不引发nameerror-如果留给运算符的表达式是一个真实的值,Python永远不会尝试求值它的右侧。

首先,我们要了解Python是如何读取十六进制数字的。

在Tokenizer.c的巨大tok_get函数上,我们:

  1. 查找第一个0x
  2. 继续读取下一个字符,只要它们在0-f范围内。

解析后的令牌0xf(因为“o”不在0-f的范围内)最终将传递给PEG解析器,解析器将其转换为十进制值15(参见附录A)。

我们仍然必须解析(1,2,3)]中的其余代码或x,这与下面的代码一样:

[15 or x in (1, 2, 3)]

由于中的具有比更高的运算符优先级,因此我们可能希望(1,2,3)中的x首先计算。

这是一个麻烦的情况,因为x不存在,并且将引发NameError

幸运的是,Python支持短路求值,因为是懒惰运算符:如果左操作数等同于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]

在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_strtoulpython/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文件中的正确部分。
  • 原推文。

 类似资料:
  • 问题内容: 为什么要用返回? 我如何获得改组后的值而不是? 问题答案: 更改x列表到位。 就地更改结构的方法通常返回None,而不是修改后的数据结构。 如果要基于现有列表创建新的随机混排列表,并按顺序保留现有列表,则可以使用输入的完整长度: 你还可以将用于排序键: 但这会调用排序(操作),而采样到输入长度仅需要O(N)操作(与所使用的过程相同,即从收缩池中换出随机值)。 演示:

  • 问题内容: 这是简单的代码,我没有得到设置位图的结果,而是得到了null。谁能告诉我我在哪里犯错了? 更新 好的,所以我无法像我想的那样将文本转换为图像。这样呢 这会创建位图吗? 问题答案: 从文档中: 返回 解码的位图;如果无法解码图像,则 返回 null。 字符串“ test”中涉及的字节不是有效的位图,对吗? 如果将文本“ test”保存在名为or 等的文件中,并试图在Windows中打开它

  • 问题内容: 为什么要用Python返回? 我如何获得改组后的值而不是? 问题答案: 更改列表 到位 。 在原位更改结构的Python API方法通常返回,而不是修改后的数据结构。 如果要基于现有列表创建 新的 随机混排列表,并按顺序保留现有列表,则可以使用输入的完整长度: 您还可以将with用于排序键: 但这会调用排序(O(NlogN)操作),而采样到输入长度仅需要O(N)操作(与所使用的过程相同

  • 问题内容: 我正在使用a 检查我的哈希密码。我有PHP 5.5: 我上车了。我已经检查了posts的值和mysql user_password_hash返回。 我不知道为什么它返回假 有任何想法吗? 问题答案: 手册中的列长度可能是问题所在: 建议将结果存储在可扩展超过60个字符的数据库列中(255个字符是一个不错的选择)。 链接

  • 问题内容: 我已经存储了在该数据库中插入并插入记录的过程。我想获取最后插入的记录的ID。返回NULL并返回正确的ID,为什么会发生?如我所读,因此最好在表上有一些触发器的情况下使用。我可以使用吗?不论触发器如何,它是否都在表的范围内返回ID? 那么问题是什么以及使用什么呢? 已编辑 问题答案: 就像奥德(Oded)所说的那样,问题在于您在执行之前要先询问身份。 作为解决方案,最好尽可能地接近运行。

  • 我正在尝试访问项目中的文件。但是getResource方法返回null。 以及eclipse工作区中项目文件夹的外观: 为什么啊?我想访问我的资产文件夹中的文件? 编辑我创建了一个jar文件,这是jar的内容: 已解决 首先,我有很多图像文件,所以我想把它们组织在一个文件夹中。我把assets文件夹放在src目录中,最后我能够访问这些文件。