为什么Python的dis不喜欢列表?

2024-10-01 09:37:32 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python(2.7.2)中,为什么

import dis
dis.dis("i in (2, 3)")

按预期工作,鉴于

^{pr2}$

加薪:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/dis.py", line 45, in dis
  disassemble_string(x)
File "/usr/lib/python2.7/dis.py", line 112, in disassemble_string
  labels = findlabels(code)
File "/usr/lib/python2.7/dis.py", line 166, in findlabels
 oparg = ord(code[i]) + ord(code[i+1])*256
IndexError: string index out of range

请注意,这不会影响Python3。在


Tags: inpyimportstringlibusrlinecode
3条回答

如果您只是尝试获取简单表达式的字节码,那么将其作为lambda传递给dis,而您的表达式作为lambda的主体是最简单的:

>>> import dis
>>> dis.dis(lambda i : i in [3,2])
  1           0 LOAD_FAST                0 (i)
              3 LOAD_CONST               2 ((3, 2))
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE

简短回答

在Python2.x中,str类型保存原始字节,因此dis假设如果向它传递一个字符串,它将获得编译的字节码。它尝试反汇编作为字节码传递的字符串,这纯粹是因为Python字节码的实现细节成功地用于i in (2,3)。不过,很明显,它返回了胡言乱语。在

在python3.x中,str类型用于stringsbytes类型用于原始字节,因此dis可以区分编译后的字节码和字符串,并假设如果获得字符串,它将获得源代码。在


冗长的回答

这是我为解决这个问题所遵循的思考过程。在

  1. 我在Python(3.2)上尝试过:

    >>> import dis
    >>> dis.dis("i in (2,3)")  
      1           0 LOAD_NAME                0 (i)
                  3 LOAD_CONST               2 ((2, 3))
                  6 COMPARE_OP               6 (in)
                  9 RETURN_VALUE
    >>> dis.dis("i in [2,3]")
      1           0 LOAD_NAME                0 (i)
                  3 LOAD_CONST               2 ((2, 3))
                  6 COMPARE_OP               6 (in)
                  9 RETURN_VALUE
    

    显然,这是有效的。

  2. 我在Python 2.7上尝试过:

    ^{pr2}$

    啊哈!还请注意,Python3.2中生成的字节码正是您所期望的(“loadi,load(2,3),test for membership,return the result”),而在Python2.7中得到的却是胡言乱语。显然,dis在2.7中将字符串反编译为字节码,而在3.2中将其编译为Python。

  3. 我查看了dis.dis的源代码。以下是要点:

    Python 2.7:

    elif isinstance(x, str):
        disassemble_string(x)
    

    Python 3.2:

       elif isinstance(x, (bytes, bytearray)): # Raw bytecode
           _disassemble_bytes(x)
       elif isinstance(x, str):    # Source code
           _disassemble_str(x)
    

    为了好玩,让我们通过向python3中的dis传递相同的字节来检查这一点:

    >>> dis.dis("i in (2,3)".encode())
              0 BUILD_MAP       26912
              3 JUMP_FORWARD    10272 (to 10278)
              6 <50>
              7 <44>
              8 <51>
              9 <41>
    

    啊哈!胡言乱语!(不过请注意,字节码随Python版本的变化而有所不同!)

dis.dis需要字节码作为参数,而不是python源代码。尽管您的第一个示例“有效”,但它没有提供任何有意义的输出。你可能想要:

import compiler, dis

code = compiler.compile("i in [2, 3]", '', 'single')
dis.dis(code)

这和预期的一样。(我只在2.7中测试过)。在

相关问题 更多 >