在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 对象 obj1
的 prop_x
变量。该字典不会在内存中再次创建,但会发生 soft copy
。 prop_x
指向dict_x
的内存位置。
当你 return object obj1
在此函数的末尾时,dict_x
超出范围但它使用的内存地址 0xdfaae0
仍然由 returned 对象 recv_obj
中的 prop_x
指向。因此,字典值 { "k1" : "v1" }
保存在内存中。
我会尽力澄清:
例如,我创建了一个在本地创建列表的函数,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 对象 obj1
的 prop_x
变量。该字典不会在内存中再次创建,但会发生 soft copy
。 prop_x
指向dict_x
的内存位置。
当你 return object obj1
在此函数的末尾时,dict_x
超出范围但它使用的内存地址 0xdfaae0
仍然由 returned 对象 recv_obj
中的 prop_x
指向。因此,字典值 { "k1" : "v1" }
保存在内存中。