I\'d like to create a new code object with the function types.CodeType() .
There is almost no documentation about this and the existing one says \"not for faint of heart\"
Example usage of the CodeType constructor may be found in the standard library, specifically Lib/modulefinder.py. If you look there, you'll see it being used to redefine the read-only co_filename
attribute on all the code objects in a file.
I recently ran into a similar use case where I had a function factory, but the generated functions always had the "generic" name in the traceback, so I had to regenerate the code objects to contain the desired name.
>>> def x(): raise NotImplementedError
...
>>> x.__name__
'x'
>>> x.__name__ = 'y'
>>> x.__name__
'y'
>>> x()
Traceback (most recent call last):
File "", line 1, in
File "", line 1, in x
NotImplementedError
>>> x.__code__.co_name
'x'
>>> x.__code__.__name__ = 'y'
Traceback (most recent call last):
File "", line 1, in
AttributeError: readonly attribute
>>> 'Gah!'
'Gah!'
But, wait, the function's __code__
member is not read-only, so we can do what the modulefinder does:
>>> from types import CodeType
>>> co = x.__code__
>>> x.__code__ = CodeType(co.co_argcount, co.co_kwonlyargcount,
co.co_nlocals, co.co_stacksize, co.co_flags,
co.co_code, co.co_consts, co.co_names,
co.co_varnames, co.co_filename,
'MyNewCodeName',
co.co_firstlineno, co.co_lnotab, co.co_freevars,
co.co_cellvars)
>>> x.__code__.co_name
'MyNewCodeName'
>>> x()
Traceback (most recent call last):
File "", line 1, in
File "", line 1, in MyNewCodeName
NotImplementedError
The thing to note in this example is that the traceback uses the co_name
attribute, not the func.__name__
attribute when producing values in the stack trace.
One more note: The above is Python 3, to make it Python 2 compatible, just leave out the second argument to the constructor (co_kwonlyargcount
).
UPDATE: Victor Stinner added a new method, 'replace', to the CodeType class in Python 3.8, which simplifies the situation quite considerably. This was done to eliminate future compatibility issues, as 3.8 also added a new 'co_posonlyargcount' argument into the call list after 'co_argcount', so at least your 3.8 and later code will be somewhat future proofed if the argument list changes again.
>>> x.__code__ = x.__code__.replace(co_name='MyNewCodeName')