Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Is there a possibility to create real copies of python functions? The most obvious choice was http://docs.python.org/2/library/copy.html but there I read:

It does “copy” functions and classes (shallow and deeply), by returning the original object unchanged;

I need a real copy, because I might change some attributes of the function.

Update:

I'm aware of all the possibilities which are mentioned in the comments. My use case is based on meta programming where I construct classes out of some declarative specifications. Complete details would be too long for SO, but basically I have a function like

def do_something_usefull(self,arg):
    self.do_work()

I will add this method to various classes. Thoses classes can be completly unrelated. Using mixin classes is not an option: I will have many such functions and would end up adding a base class for each function. My current "workaround" would be to wrap this function in a "factory" like this:

def create_do_something():
    def do_something_usefull(self,arg):
        self.do_work()

That way I always get a new do_something_useful function, but I have to wrap all my functions like this.

You can trust me, that I'm aware, that this is no "normal" OO programming. I know how to solve something like that "normally". But this is a dynamic code generator and I would like to keep everything as lightweight and simple as possible. And as python functions are quite normal objects, I don't think it's too strange to ask how to copy them!?

Use copy.deepcopy if you really must. But I think there's a deeper design flaw somewhere. Why do you want to copy functions in the first place? – inspectorG4dget Nov 21, 2012 at 22:27 Can you help us understand a bit about what you want to do -- your question is a little strange/vague. In the thousands of lines of python I've written, I've never copied a function. – jfaller Nov 21, 2012 at 22:28 If you need to maintain state, why not use classes and instances? Why functions that need to be copied somehow? – Praveen Gollakota Nov 21, 2012 at 22:29 If you're changing attributes on a function you're probably better off wrapping the function in an object then changing attributes on the object. It will make your code cleaner. If you add a __call__ method to your object it can be called just like a function. – Peter Graham Nov 21, 2012 at 22:30 I don't see why treating function like any other object should be a problem, in python. I do have the same need: decorated functions are passed to internal and external code which expect a function object. Copying a function in order to change its decoration is thus useful and working around with objects that look-a-like function but are not is just overly complicated. – Juh_ Aug 7, 2013 at 11:32 def copy_func(f): """Based on http://stackoverflow.com/a/6528148/190597 (Glenn Maynard)""" g = types.FunctionType(f.__code__, f.__globals__, name=f.__name__, argdefs=f.__defaults__, closure=f.__closure__) g = functools.update_wrapper(g, f) g.__kwdefaults__ = f.__kwdefaults__ return g def f(arg1, arg2, arg3, kwarg1="FOO", *args, kwarg2="BAR", kwarg3="BAZ"): return (arg1, arg2, arg3, args, kwarg1, kwarg2, kwarg3) f.cache = [1,2,3] g = copy_func(f) print(f(1,2,3,4,5)) print(g(1,2,3,4,5)) print(g.cache) assert f is not g

yields

(1, 2, 3, (5,), 4, 'BAR', 'BAZ')
(1, 2, 3, (5,), 4, 'BAR', 'BAZ')
[1, 2, 3]
import functools
def copy_func(f):
    """Based on http://stackoverflow.com/a/6528148/190597 (Glenn Maynard)"""
    g = types.FunctionType(f.func_code, f.func_globals, name=f.func_name,
                           argdefs=f.func_defaults,
                           closure=f.func_closure)
    g = functools.update_wrapper(g, f)
    return g
def f(x, y=2):
    return x,y
f.cache = [1,2,3]
g = copy_func(f)
print(f(1))
print(g(1))
print(g.cache)
assert f is not g

yields

(1, 2)
(1, 2)
[1, 2, 3]
                functools.update_wrapper would update all the metadata other then __kwdefaults__ like __doc__ and __module__
– Tadhg McDonald-Jensen
                Jun 17, 2016 at 19:10
                Currently, this answer is based on Glenn Maynard's answer to a similar question.  Under that same question, there is an updated answer by Aaron Hall which is very similar to this answer. Aaron updates the new dict based on the old, while this answer uses update_wrapper to update the attributes individually. I am wondering (in the case of Python 3) whether or not the outcome is always the same.
– Ben Mares
                Feb 19, 2019 at 10:57
                @BenMares: With g = functools.update_wrapper(g, f), you get g.__wrapped__ which equals f. If you use fn.__dict__.update(f.__dict__) you do not get the __wrapped__ attribute. I'm not aware of any other difference due to update_wrapper.
– unutbu
                Feb 19, 2019 at 13:06
                @BenMares: A more dramatic difference is made by the inclusion of g.__kwdefaults__ = f.__kwdefaults__.  With this, g(1,2,3) returns (1, 2, 3, (), 'FOO', 'BAR', 'BAZ'). Without it, g(1,2,3) raises TypeError: f() missing 3 required positional arguments: 'arg1', 'arg2', and 'arg3'.
– unutbu
                Feb 19, 2019 at 13:06