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

2024-03-29 10:10:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我想澄清一下:

例如,我创建了一个函数,该函数在本地创建一个列表并返回它。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是使用deepcopy还是类似的东西来制作l? 不管我用函数返回哪种类型的对象,它都不会受到对该函数的后续调用的影响? (只要对象是在函数中本地创建的)

如果我说得不够清楚,请毫不犹豫地告诉我。 谢谢


Tags: of对象函数in列表returndefcreate
3条回答

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

当你第二次运行这个函数时,整个函数都会重新运行——它没有内存,就像上次的sublist1[1, 2, 3]“那样。

你还没有复制列表[1, 2, 3]。你已经创建了两次。


注意,如果您使用像^{}这样的缓存装饰器,您将得到令人惊讶的结果:

>>> @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确实有上一个结果的内存,并且返回相同的对象

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

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

示例代码

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被分配给类对象obj1prop_x变量。dict不会在内存中再次创建,但会发生soft copyprop_x指向dict_x的内存位置。

当您在函数末尾返回对象obj1时,dict_x超出了范围,但它使用的内存地址0xdfaae0仍由返回对象prop_x中的recv_obj指向。因此,dict值{ "k1" : "v1" }保存在内存中。

相关问题 更多 >