假设我有两个列表:
>>> l1=[1,2,3,4]
>>> l2=[11,12,13,14]
我可以将这些列表放入元组或字典中,看起来它们都是对原始列表的引用:
>>> t=(l1,l2)
>>> d={'l1':l1, 'l2':l2}
>>> id(l1)==id(d['l1'])==id(t[0])
True
>>> l1 is d['l1'] is t[0]
True
因为它们是引用,我可以更改 l1
并且元组和字典中引用的数据会相应地更改:
>>> l1.append(5)
>>> l1
[1, 2, 3, 4, 5]
>>> t
([1, 2, 3, 4, 5], [11, 12, 13, 14])
>>> d
{'l2': [11, 12, 13, 14], 'l1': [1, 2, 3, 4, 5]}
包括如果我在字典 d
中附加引用或在元组 t
中附加可变引用:
>>> d['l1'].append(6)
>>> t[0].append(7)
>>> d
{'l2': [11, 12, 13, 14], 'l1': [1, 2, 3, 4, 5, 6, 7]}
>>> l1
[1, 2, 3, 4, 5, 6, 7]
如果我现在将 l1
设置为一个新列表,原始列表的引用计数会减少:
>>> sys.getrefcount(l1)
4
>>> sys.getrefcount(t[0])
4
>>> l1=['new','list']
>>> l1 is d['l1'] is t[0]
False
>>> sys.getrefcount(l1)
2
>>> sys.getrefcount(t[0])
3
并且附加或更改 l1
不会更改 d['l1']
或 t[0]
,因为它现在是一个新引用。间接引用的概念是 covered fairly well在 Python 文档中,但不完全。
我的问题:
可变对象总是是引用吗?您是否可以总是假设修改它会修改原始文件(除非您特别使用
l2=l1[:]
那种习语制作副本)?我可以在 Python 中汇总所有相同引用的列表吗?即,某些函数
f(l1)
返回['l1', 'd', 't']
如果所有这些都引用同一个列表?我的假设是,无论如何,只要有人引用数据,数据就会一直有效。
即:
l=[1,2,3] # create an object of three integers and create a ref to it
l2=l # create a reference to the same object
l=[4,5,6] # create a new object of 3 ints; the original now referenced
# by l2 is unchanged and unmoved
最佳答案
1) 通过引用修改可变对象将总是修改“原始对象”。老实说,这是对引用的误解。较新的引用与任何其他引用一样都是“原始”。只要两个名称都指向同一个对象,通过另一个名称修改对象将反射(reflect)在通过另一个名称访问时。
2) 与您想要的不完全一样。 gc.get_referrers
返回对该对象的所有 引用。
>>> l = [1, 2]
>>> d = {0: l}
>>> t = (l, )
>>> import gc
>>> import pprint
>>> pprint.pprint(gc.get_referrers(l))
[{'__builtins__': <module '__builtin__' (built-in)>,
'__doc__': None,
'__name__': '__main__',
'__package__': None,
'd': {0: [1, 2]},
'gc': <module 'gc' (built-in)>,
'l': [1, 2],
'pprint': <module 'pprint' from '/usr/lib/python2.6/pprint.pyc'>,
't': ([1, 2],)}, # This is globals()
{0: [1, 2]}, # This is d
([1, 2],)] # this is t
请注意,l
引用的实际对象不包含在返回的列表中,因为它不包含对自身的引用。 globals()
被返回,因为它确实包含对原始列表的引用。
3) 如果有效是指“不会被垃圾收集”,那么这是正确的,除非出现极不可能的错误。如果垃圾收集器“窃取”了您的数据,那就太遗憾了。
关于Python基础资料引用,相同引用列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4557223/