Say I have two lists:
>>> l1=[1,2,3,4]
>>> l2=[11,12,13,14]
I can put those lists in a tuple, or dictionary, and it appears that they are all references back to the original list:
>>> 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
Since they are references, I can change l1 and the referred data in the tuple and dictionary change accordingly:
>>> 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]}
Including if I append the reference in the dictionary d or mutable reference in the tuple 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]
If I now set l1 to a new list, the reference count for the original list decreases:
>>> 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
And appending or changing l1 does not change d['l1'] or t[0] since it now a new reference. The notion of indirect references is covered fairly well in the Python documents but not completely.
My questions:
-
Is a mutable object always a reference? Can you always assume that modifying it modifies the original (Unless you specifically make a copy with
l2=l1[:]kind of idiom)? -
Can I assemble a list of all the same references in Python? ie, Some function
f(l1)that returns['l1', 'd', 't']if those all those are referring to the same list? -
It is my assumption that no matter what, the data will remain valid so long as there is some reference to it.
ie:
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) Modifying a mutable object through a reference will always modify the “original”. Honestly, this is betraying a misunderstanding of references. The newer reference is just as much the “original” as is any other reference. So long as both names point to the same object, modifying the object through either name will be reflected when accessed through the other name.
2) Not exactly like what you want.
gc.get_referrersreturns all references to the object.Note that the actual object referenced by
lis not included in the returned list because it does not contain a reference to itself.globals()is returned because that does contain a reference to the original list.3) If by valid, you mean “will not be garbage collected” then this is correct barring a highly unlikely bug. It would be a pretty sorry garbage collector that “stole” your data.