How to create a code object in python?

前端 未结 2 1390
醉话见心
醉话见心 2021-01-31 05:15

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\"

2条回答
  •  深忆病人
    2021-01-31 05:56

    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')
    

提交回复
热议问题