Yann
Yann

Reputation: 544

In python, returning an object created in a function body makes a deep copy of it?

I'll try to clarify:

For example, I make a function that locally creates a list, and return it. How does Python create the returned list that exist outside the function body ? Does it use "deepcopy" (or something similar) ?

In [50]: def create_list():
    ...:     sublist1 = [1,2,3]
    ...:     sublist2 = [4,5,6]
    ...:     list_of_lists=[sublist1,sublist1,sublist2]
    ...:     return list_of_lists
    ...: 

In [51]: l=create_list()

In [52]: l
Out[52]: [[1, 2, 3], [1, 2, 3], [4, 5, 6]]

In [53]: l[0].append(4)

In [54]: l
Out[54]: [[1, 2, 3, 4], [1, 2, 3, 4], [4, 5, 6]]

Here, the returned list l still contains the sublists. And l[0] and l[1] still reference the same sublist (which is normal Python behavior). So the list and its structure were copied.

And if I call once again create_list() :

In [55]: l2=create_list()

In [56]: l2
Out[56]: [[1, 2, 3], [1, 2, 3], [4, 5, 6]]

In [57]: l
Out[57]: [[1, 2, 3, 4], [1, 2, 3, 4], [4, 5, 6]]

A new list l2 has been created, but l is unaffected, which means it does exist outside the function, and its sublists are its own, not references to sublists that would still exist in the function body.

So my question : does Python used deepcopy or something similar to make l ? Not matter what kind of object I return with a function, it will be unaffected by subsequent call to this function ? (as long as the object was created locally in the function)

Do not hesitate to tell me if I'm not clear enough. Thanks,

Upvotes: 7

Views: 10909

Answers (3)

gsinha
gsinha

Reputation: 1185

This might not directly answer this question but should help clarify related concept.

If you create a nested object inside a function and return it, the object will continue to exist. It would not go out of scope even though the function ended.

Example Code

class Some_Class (object):
    prop_x = None
    def __init__(self, prop_x ):
        self.prop_x = prop_x
    def __repr__(self):
        return "prop_x = "+repr (self.prop_x)

def fx ():
    dict_x = { "k1" : "v1" }
    print hex ( id (dict_x) )
    obj1 = Some_Class ( prop_x = dict_x )
    print hex ( id (obj1.prop_x) )
    print "obj1 is "+repr( obj1 )
    return obj1

recv_obj = fx ()

print "recv_obj is "+repr( recv_obj ) 
print hex ( id (recv_obj.prop_x) ) 

Output

0xdfaae0
0xdfaae0
obj1 is prop_x = {'k1': 'v1'}
recv_obj is prop_x = {'k1': 'v1'}
0xdfaae0 

A dict, dict_x, is assigned to prop_x variable of a Class object obj1. The dict is not created again in memory but a soft copy takes place. prop_x points to the memory location of dict_x.

When you return object obj1 at the end of this function, dict_x goes out of scope but the memory address used by it, 0xdfaae0, is still pointed by prop_x in the returned object recv_obj. So, the dict values { "k1" : "v1" } are preserved in memory.

Upvotes: 4

Craig Burgler
Craig Burgler

Reputation: 1779

Variables in Python are pointers to objects. So a function would return a pointer to an object created in the function, obviating the need for copying return values.

Upvotes: 0

Eric
Eric

Reputation: 97601

When you run the function the second time, the entire function is rerun - it has no memory along the lines of "last time, sublist1 was [1, 2, 3]".

You haven't copied the list [1, 2, 3]. You've created it twice.


Note that if you use a caching decorator like @functools.lru_cache, you'll get surprising results:

>>> @lru_cache()
... def create_list():
...     sublist1 = [1,2,3]
...     sublist2 = [4,5,6]
...     list_of_lists=[sublist1,sublist1,sublist2]
...     return list_of_lists
...
>>> l = create_list(); l
[[1, 2, 3], [1, 2, 3], [4, 5, 6]]
>>> l[0].append(4); l
[[1, 2, 3, 4], [1, 2, 3, 4], [4, 5, 6]]
>>> create_list()
[[1, 2, 3, 4], [1, 2, 3, 4], [4, 5, 6]]

Because in this case, python does have a memory of the previous result, and returns the same object

Upvotes: 3

Related Questions