在python中,返回一个在函数体中创建的对象是对它的深拷贝吗?

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

我会尽力澄清:

例如,我创建了一个在本地创建列表的函数,return 它。 Python 如何创建存在于函数体外部的 returned 列表?它使用 "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]]

在这里,returned 列表 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 或类似于 make l 的东西? 无论我 return 带有一个函数的是哪种对象,它都不会受到后续对该函数的调用的影响? (只要对象是在函数本地创建的)

如果我不够清楚,请随时告诉我。 谢谢,

当您第二次 运行 函数时,整个函数重新 运行 - 它没有 "last time, sublist1 was [1, 2, 3]"[=28 的记忆=].

您还没有复制列表[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确实有对之前结果的记忆,和returns同一个对象

Python 中的变量是指向对象的指针。因此,函数将 return 指向在函数中创建的对象的指针,从而避免了复制 return 值的需要。

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

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

示例代码

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

当你 return object obj1 在此函数的末尾时,dict_x 超出范围但它使用的内存地址 0xdfaae0 仍然由 returned 对象 recv_obj 中的 prop_x 指向。因此,字典值 { "k1" : "v1" } 保存在内存中。