How to create a copy of a python function

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!?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

In Python3:

import types
import functools

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]

In Python2:

import types
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]


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x