Each variable in Python is a reference.
For lists, you focus on the results of the append() method and lose the appearance of a larger image of Python data structures. There are other methods on lists, and there are advantages and consequences to building a list. It is useful to think of the list as representing other objects mentioned in the list. They do not “contain” anything but the rules and methods of accessing the data referenced by the objects within them.
The list.append(x) method , in particular, is equivalent to l[len(l):]=[list]
So:
>>> l1=range(3) >>> l2=range(20,23) >>> l3=range(30,33) >>> l1[len(l1):]=[l2] # equivalent to 'append' for subscriptable sequences >>> l1[len(l1):]=l3 # same as 'extend' >>> l1 [0, 1, 2, [20, 21, 22], 30, 31, 32] >>> len(l1) 7 >>> l1.index(30) 4 >>> l1.index(20) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: list.index(x): x not in list >>> 20 in l1 False >>> 30 in l1 True
By placing the list constructor around l2 in l1[len(l1):]=[l2] or by calling l.append(l2) , you will create a link bound to l2. If you change l2, the links will also show the change. The length of this in the list is one element - a link to the attached sequence.
Without the constructor shortcut, as in l1[len(l1):]=l3 , you copy each element of the sequence.
If you use other common list methods, such as l.index(something) or in , you will not find elements inside the data links. l.sort() will not be sorted properly. These are “small” operations on an object, and using l1[len(l1):]=[l2] you create a recursive data structure.
If you use l1[len(l1):]=l3 , you create a true (shallow) copy of the elements in l3 .
These are fairly fundamental Python idioms, and most of the time they "do the right thing." However, you may get unexpected results, for example:
>>> m=[[None]*2]*3 >>> m [[None, None], [None, None], [None, None]] >>> m[0][1]=33 >>> m [[None, 33], [None, 33], [None, 33]] # probably not what was intended... >>> m[0] is m[1] is m[2] # same object, that why they all changed True
Some Python newbies are trying to create multidimensionality by doing something like m=[[None]*2]*3 The first replication sequence works as expected; he creates 2 copies of None . This is the second problem: it creates three copies of the link to the first list. Thus, entering m[0][1]=33 modifies the list inside the list associated with m, and then all related links change to show this change.
Compare with:
>>> m=[[None]*2,[None]*2,[None]*2] >>> m [[None, None], [None, None], [None, None]] >>> m[0][1]=33 >>> m [[None, 33], [None, None], [None, None]]
You can also use nested lists to do the same:
>>> m=[[ None for i in range(2)] for j in range(3)] >>> m [[None, None], [None, None], [None, None]] >>> m[0][1]=44 >>> m [[None, 44], [None, None], [None, None]] >>> m[0] is m[1] is m[2] # three different lists.... False
For listings and links, Fredrik Lundh has this text for good input.
Regarding your specific questions:
1) In Python, Everything is a label or a reference to an object. There is no “original” (C ++ concept), and there is no difference between a “link”, a pointer, or actual data (C / Perl concept)
2) Fredrik Lund has a great analogy regarding a reference to a question like this :
Just like you get the name that the cat you found on the porch: cat (the object) cannot tell you its name, and in fact it does not bother - so the only way to find out what he called is to ask all your neighbors ( namespaces) if it's their cat (object) ...
.... and do not be surprised if you find out that he is known by many names, or if there is no name at all!
You can find this list with some effort, but why? Just call him what you call - like a cat found.
3) True.