Segundo a documentação, o módulo dis suporta a análise do bytecode do CPython através da desmontagem do código compilado. O código extraído é o mesmo código de 3 endereços usado pelo interpretador.
Exemplo 1
Considere o seguinte código:
import dis
def soma(val1, val2):
return val1 + val2
dis.dis(soma)
Salve esse código como python-dis-1.py. Ao executar este script obtemos a seguinte saída:
4 0 LOAD_FAST 0 (val1)
3 LOAD_FAST 1 (val2)
6 BINARY_ADD
7 RETURN_VALUE
Neste bytecode gerado pela definição da função soma é claramente visto que é primeiro carregado o primeiro argumento, depois o segundo argumento e então é executada a operação de adição. Por fim é retornado o valor do “registrador”.
Python é interessante porque é possível mostrar de forma mais clara e rápida a transformação de uma linguagem de alto nível para uma linguagem de baixo nível, neste caso, um código intermediário que é usado pela máquina virtual que interpreta o bytecode.
Exemplo 2
Considere o seguinte código:
import dis
def fatorial(n):
if n == 1: return 1
else: return fatorial(n-1)
dis.dis(fatorial)
Se salvarmos o código e o executarmos, obtemos a seguinte saída:
4 0 LOAD_FAST 0 (n)
3 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_FALSE 16
12 LOAD_CONST 1 (1)
15 RETURN_VALUE
5 >> 16 LOAD_GLOBAL 0 (fatorial)
19 LOAD_FAST 0 (n)
22 LOAD_CONST 1 (1)
25 BINARY_SUBTRACT
26 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
29 RETURN_VALUE
30 LOAD_CONST 0 (None)
33 RETURN_VALUE
Obtemos um código bem diferente, mas em suma é o mesmo bytecode intermediário, que neste caso implementa empilhamentos de chamadas da função fatorial.
Deixo a cargo do leitor ler e se aprofundar na máquina virtual do Python. Entender como a máquina virtual do Python funciona é importante, mas ainda mais importante é entender e saber escrever programas bem otimizados. O leitor pode encontrar mais detalhes também aqui.
Publicado originalmente em: https://medium.com/@gvfs/visualizando-o-bytecode-do-python-551703e1573d