from cs1graphics import *
from math import sqrt
numLinks = 50
restingLength = 20.0
totalSeparation = 630.0
elasticityConstant = 0.005
gravityConstant = 0.110
epsilo
If it helps, here is the explanation taken directly from page 189 of the book (Object Oriented Programming in Python), immediately below the presentation of the piece of code given:
"An important subtlety in our approach is seen at line 52. This line causes oldChain to be a copy of the chain. Note that this is quite different semantics from the command oldChain = chain, which would simply make the identifier oldChain reference the same underlying list. The need for this copy is as follows. The inner for loop is used to recompute the position of each interior point of the chain, one by one. We want to do all of those computations based upon a coherent state of the chain. If we had not made a copy, we would run into the following trouble. The adjustment to the second point in the chain depends on the positions of the first and third points. Suppose that we were to make that adjustment and then continue. The next step would be to calculate the adjustment to the third point, which depends on the positions of the second and fourth points. But now there would be a discrepancy between the preceding position of the second point and its updated position. We want to use the preceding position of the second point for consistency. For this reason, we compute all forces based upon the copy of the old chain."
oldchain = list(chain)
oldchain points to a new list that is not chain (not the same object) but has the same contents.
*As other answers have mentioned, this is makes oldchain a "shallow copy" of chain.
oldchain = chain
oldchain just points to chain, both point to same object
However, note that oldchain = []
and oldchain = list()
are functionally the same since both are creating an empty list. It becomes different when other references (ie. chain
) are involved.
list(chain)
returns a shallow copy of chain
, it is equivalent to chain[:]
.
If you want a shallow copy of the list then use list()
, it also used sometimes to get all the values from an iterator.
Difference between y = list(x)
and y = x
:
Shallow copy:
>>> x = [1,2,3]
>>> y = x #this simply creates a new referece to the same list object
>>> y is x
True
>>> y.append(4) # appending to y, will affect x as well
>>> x,y
([1, 2, 3, 4], [1, 2, 3, 4]) #both are changed
#shallow copy
>>> x = [1,2,3]
>>> y = list(x) #y is a shallow copy of x
>>> x is y
False
>>> y.append(4) #appending to y won't affect x and vice-versa
>>> x,y
([1, 2, 3], [1, 2, 3, 4]) #x is still same
Deepcopy:
Note that if x
contains mutable objects then just list()
or [:]
are not enough:
>>> x = [[1,2],[3,4]]
>>> y = list(x) #outer list is different
>>> x is y
False
But inner objects are still references to the objects in x:
>>> x[0] is y[0], x[1] is y[1]
(True, True)
>>> y[0].append('foo') #modify an inner list
>>> x,y #changes can be seen in both lists
([[1, 2, 'foo'], [3, 4]], [[1, 2, 'foo'], [3, 4]])
As the outer lists are different then modifying x will not affect y and vice-versa
>>> x.append('bar')
>>> x,y
([[1, 2, 'foo'], [3, 4], 'bar'], [[1, 2, 'foo'], [3, 4]])
To handle this use copy.deepcopy
.
It is true that list([])
is functionally equivalent to []
, both creating a new empty list.
But x = list(y)
is not the same as x = y
. The formers makes a shallow copy, and the latter creates a new reference to the existing list.
Note that list([])
is inefficient -- it creates a new empty list (by doing []
), then copies it, resulting with another empty list (by doing list(...)
), then deallocates the original, unreferenced, list.