Ответ 1
Краткий ответ
В Python 2.x тип str
содержит необработанные байты, поэтому dis
предполагает, что если вы передадите ему строку, она получает скомпилированный байт-код. Он пытается разобрать строку, которую вы передаете ей в качестве байт-кода, и - чисто из-за деталей реализации байт-кода Python - преуспевает для i in (2,3)
. Очевидно, однако, он возвращает тарабарщину.
В Python 3.x тип str
предназначен для строк, а типы bytes
- для необработанных байтов, поэтому dis
может различать скомпилированный байт-код и строки - и предполагает, что он получает исходный код, если он получает строку.
Длинный ответ
Здесь мы задумали процесс, который я выполнил для этого.
-
Я попробовал это на своем 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
Очевидно, что это работает.
-
Я попробовал это на Python 2.7:
>>> import dis >>> dis.dis("i in (2,3)") 0 BUILD_MAP 26912 3 JUMP_FORWARD 10272 (to 10278) 6 DELETE_SLICE+0 7 <44> 8 DELETE_SLICE+1 9 STORE_SLICE+1 >>> dis.dis("i in [2,3]") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Python27\lib\dis.py", line 45, in dis disassemble_string(x) File "C:\Python27\lib\dis.py", line 112, in disassemble_string labels = findlabels(code) File "C:\Python27\lib\dis.py", line 166, in findlabels oparg = ord(code[i]) + ord(code[i+1])*256 IndexError: string index out of range
Ага! Также обратите внимание, что сгенерированный байт-код в Python 3.2 - это то, что вы ожидаете ( "load
i
, load(2,3)
, test for membership, return result" ), а то, что вы получили в Python 2.7, - тарабарщина. Ясно, чтоdis
декомпилирует строку как байт-код в 2.7, но компилирует ее как Python в 3.2. -
Я просмотрел исходный код для
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)
Просто для удовольствия, пусть это проверит, передав те же байты в
dis
в Python 3:>>> 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>
Ага! Gibberish! (Хотя обратите внимание, что это немного другая тарабарщина - байт-код изменился с версией Python!)