在python中,返回在函数体中创建的对象会对其进行深层复制吗?

时间:2015-04-19 10:39:22

标签: python copy return-value deep-copy

我会试着澄清一下:

例如,我创建一个本地创建列表的函数,然后返回它。 Python如何创建函数体外存在的返回列表?它是否使用“deepcopy”(或类似的东西)?

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

此处,返回的列表l仍包含子列表。并且l[0]l[1]仍然引用相同的子列表(这是正常的Python行为)。所以列表及其结构被复制了。

如果我再次打电话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]]

已创建新列表l2,但l未受影响,这意味着它确实存在于函数外部,其子列表是它自己的,而不是对仍然存在于其中的子列表的引用功能体。

所以我的问题是:Python是否使用了深度复制或类似的东西来制作l? 无论我使用函数返回什么类型的对象,它都不会受到后续调用此函数的影响? (只要对象是在函数中本地创建的)

如果我不够清楚,请不要犹豫告诉我。 谢谢,

3 个答案:

答案 0 :(得分:2)

当您第二次运行该功能时,整个功能将重新运行 - 它没有"内存中的内存; sublist1[1, 2, 3]&#34 ;

您尚未复制列表[1, 2, 3]。您已经创建了两次。


请注意,如果你使用像@functools.lru_cache这样的缓存装饰器,你会得到令人惊讶的结果:

>>> @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]]

因为在这种情况下,python确实具有前一个结果的内存,并返回相同的对象

答案 1 :(得分:2)

这可能不会直接回答这个问题,但应该有助于澄清相关概念。

如果在函数内创建嵌套对象并将其返回,则该对象将继续存在。即使功能结束,它也不会超出范围。

示例代码

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

输出

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

dict dict_x被分配给Class对象prop_x的{​​{1}}变量。 dict不会在内存中再次创建,但会发生obj1soft copy指向prop_x的内存位置。

当您在此函数结束时返回对象dict_x时,obj1超出范围,但dict_x仍然指向它所使用的内存地址0xdfaae0在返回的对象prop_x中。因此,dict值recv_obj保留在内存中。

答案 2 :(得分:0)

Python中的变量是指向对象的指针。因此,函数将返回指向函数中创建的对象的指针,从而无需复制返回值。