I wrote at length about this here so I won't repeat that but will give some summary comments.
It is definitely doable, but I wonder how generally useful it will be. The link goes into how to run and write out such stuff.
Bytecode is subject to change both in terms of opcode, or opcode names, or semantics of the opcodes between versions. In fact, in Python 3.6 and beyond a bytecode becomes a wordcode.
If you however do decide to go down this path xdis recently added a list2bytecode()
function to do just this.
If you prefer to work in a text file as most assembly code is written, I wrote xasm for this. Here is some sample assembly in the format that this can use:
# Python bytecode 3.6 (3379)
# Method Name: five
# Filename: /tmp/five.pl
# Argument count: 0
# Kw-only arguments: 0
# Number of locals: 0
# Stack size: 1
# Flags: 0x00000043 (NOFREE | NEWLOCALS | OPTIMIZED)
# First Line: 1
# Constants:
# 0: None
# 1: 5
2:
LOAD_CONST (5)
RETURN_VALUE
# Method Name: <module>
# Filename: /tmp/five.pl
# Argument count: 0
# Kw-only arguments: 0
# Number of locals: 0
# Stack size: 2
# Flags: 0x00000040 (NOFREE)
# First Line: 1
# Constants:
# 0: <code object five at 0x0000>
# 1: 'five'
# 2: None
# Names:
# 0: five
# 1: print
1:
LOAD_CONST 0 (<code object five at 0x0000>)
LOAD_CONST ('five')
MAKE_FUNCTION 0
STORE_NAME (five)
3:
LOAD_NAME (print)
LOAD_NAME (five)
CALL_FUNCTION 0
CALL_FUNCTION 1
POP_TOP
LOAD_CONST (None)
RETURN_VALUE