I'm seeing some behavior that I don't understand. I thought the bytecode of a python function is what gets executed to produce a result, but here I have 2 different lambda functions, that have the same exact bytecode, but obviously do different things. How can this be?
a = lambda x: x+4
b = lambda y: y+3
print('a = ', a.__code__.co_code)
print('b = ', b.__code__.co_code)
print(a(1), b(1))
Produces this output:
a = b'|\x00\x00d\x01\x00\x17S'
b = b'|\x00\x00d\x01\x00\x17S'
5 4
Byte-code is not the only thing in the code object. If you dissassemble the functions using dis.dis you can see what is happening:
>>> import dis
>>> a = lambda x: x + 4
>>> b = lambda y: y + 3
>>> dis.dis(a)
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (4)
6 BINARY_ADD
7 RETURN_VALUE
>>> dis.dis(b)
1 0 LOAD_FAST 0 (y)
3 LOAD_CONST 1 (3)
6 BINARY_ADD
7 RETURN_VALUE
What is happening is that there is also a tuple of constants assosciated with the code objects. The byte code just says to load the constant at an index from that tuple. They both have the same byte code, but load different values from the tuple. You can see it with the co_consts attribute:
>>> a.__code__.co_consts
(None, 4)
>>> b.__code__.co_consts
(None, 3)
You can change this too to make a different function:
>>> import types
>>> c_code = types.CodeType(
a.__code__.co_argcount, a.__code__.co_kwonlyargcount, a.__code__.co_nlocals,
a.__code__.co_stacksize, a.__code__.co_flags, a.__code__.co_code, (None, 5),
a.__code__.co_names, a.__code__.co_varnames, a.__code__.co_filename,
a.__code__.co_name, a.__code__.co_firstlineno, a.__code__.co_lnotab,
a.__code__.co_freevars, a.__code__.co_cellvars
)
>>> c = types.FunctionType(c_code, globals())
>>> a(0)
4
>>> c(0)
5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With