How can I make a deepcopy of a function in Python?
The FunctionType constructor is used to make a deep copy of a function.
import typesdef copy_func(f, name=None): return types.FunctionType(f.func_code, f.func_globals, name or f.func_name, f.func_defaults, f.func_closure)def A(): """A""" passB = copy_func(A, "B")B.__doc__ = """B"""
My goal is to have two functions with the same implementation but with different docstrings.
Most users will do this, say the original function is in old_module.py
:
def implementation(arg1, arg2): """this is a killer function"""
and in new_module.py
from old_module import implementation as _implementationdef implementation(arg1, arg2): """a different docstring""" return _implementation(arg1, arg2)
This is the most straightforward way to reuse functionality. It is easy to read and understand the intent.
Nevertheless, perhaps you have a good reason for your main question:
How can I make a deepcopy of a function in Python?
To keep this compatible with Python 2 and 3, I recommend using the function's special __dunder__
attributes. For example:
import typesdef copy_func(f, name=None): ''' return a function with same code, globals, defaults, closure, and name (or provide a new name) ''' fn = types.FunctionType(f.__code__, f.__globals__, name or f.__name__, f.__defaults__, f.__closure__) # in case f was given attrs (note this dict is a shallow copy): fn.__dict__.update(f.__dict__) return fn
And here's an example usage:
def main(): from logging import getLogger as _getLogger # pyflakes:ignore, must copy getLogger = copy_func(_getLogger) getLogger.__doc__ += '\n This function is from the Std Lib logging module.\n ' assert getLogger.__doc__ is not _getLogger.__doc__ assert getLogger.__doc__ != _getLogger.__doc__
A commenter says:
This can’t work for built‑in functions
Well I wouldn't do this for a built-in function. I have very little reason to do this for functions written in pure Python, and my suspicion is that if you are doing this, you're probably doing something very wrong (though I could be wrong here).
If you want a function that does what a builtin function does, and reuses the implementation, like a copy would, then you should wrap the function with another function, e.g.:
_sum = sumdef sum(iterable, start=0): """sum function that works like the regular sum function, but noisy""" print('calling the sum function') return _sum(iterable, start)