9
from cs1graphics import *
from math import sqrt

numLinks = 50
restingLength = 20.0
totalSeparation = 630.0
elasticityConstant = 0.005
gravityConstant = 0.110
epsilon     = 0.001

def combine(A,B,C=(0,0)):
    return (A[0] + B[0] + C[0], A[1] + B[1] + C[1])

def calcForce(A,B):
    dX = (B[0] - A[0])
    dY = (B[1] - A[1])
    distance = sqrt(dX*dX+dY*dY)
    if distance > restingLength:
        stretch = distance - restingLength
        forceFactor = stretch * elasticityConstant
    else:
        forceFactor = 0
    return (forceFactor * dX, forceFactor * dY)                 #return a tuple


def drawChain(chainData, chainPath, theCanvas):
    for k in range(len(chainData)):
        chainPath.setPoint(Point(chainData[k][0], chainData[k][1]),k)
    theCanvas.refresh()                             #refresh canvas

chain = []                                                             #chain here
for k in range(numLinks + 1):
    X = totalSeparation * k / numLinks
    chain.append( (X,0.0) )

paper = Canvas(totalSeparation, totalSeparation)
paper.setAutoRefresh(False)
curve = Path()
for p in chain:
    curve.addPoint(Point(p[0], p[1]))
paper.add(curve)
graphicsCounter = 100

somethingMoved = True
while somethingMoved:
    somethingMoved = False
    oldChain = list(chain)                                             #oldChain here
    for k in range(1, numLinks):
        gravForce = (0, gravityConstant)
        leftForce = calcForce(oldChain[k], oldChain[k-1])
        rightForce = calcForce(oldChain[k], oldChain[k+1])
        adjust = combine(gravForce, leftForce, rightForce)
        if abs(adjust[0]) > epsilon or abs(adjust[1]) > epsilon:
            somethingMoved = True
        chain[k] = combine(oldChain[k], adjust)
    graphicsCounter -= 1
    if graphicsCounter == 0:
        drawChain(chain, curve, paper)
        graphicsCounter = 100

curve.setBorderWidth(2)
drawChain(chain, curve, paper)

I was told that list([]) == []. So why is this code doing
oldChain = list(chain) instead of oldChain = chain

it's the same thing so it does not matter either way to do it?

5
  • 2
    Is this not your code? Commented Jul 11, 2013 at 16:59
  • 4
    It would have been better if you only posted the piece of code relevant to the question. It's not immediately clear what line you're referring to Commented Jul 11, 2013 at 17:05
  • @2rs2ts its code from Object-Oriented Programming in Python Commented Jul 20, 2013 at 19:20
  • You say that you were told that list([]) == []. However these forms are not equivalent. list() is like [], list([]) is like list(list()). All of them result into an empty list [], and all empty lists compare equal to each other: [] == [] is True Commented Aug 4, 2013 at 8:17
  • @AnttiHaapala you completely missed the point of the question. read accepted answer. Commented Aug 4, 2013 at 17:32

4 Answers 4

16

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.

Sign up to request clarification or add additional context in comments.

1 Comment

You should expand on this example to show the difference between a = b and a = list(b) in terms of reference as well, then this answer would be pretty complete. Add an example showing that modifying a in the first example will "modify b" as well, contrast that with the second statement.
3

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.

4 Comments

People tend to write lst = [] but you can also write lst = list(), it's also functionally equivalent.
@2rs2ts Using literals, however, is faster and better style.
@Lattyware I didn't realize it was faster, but imeit.timeit(stmt='lst = []', number=100000000) resulted in 3.7173891067504883 while timeit.timeit(stmt='lst = list()', number=100000000) resulted in 12.700881958007812. Wow!
@2rs2ts The function has a lot of overhead, as where a literal has a lot of optimisations applied due top it's nature. Obviously, it's not likely speed will be a problem, so readability is the more important factor.
2
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.

Comments

1

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."

2 Comments

ah I see. but must be different edition of the book? I just checked page 211 and there is no such explanation there. In fact the code above is on page 192 fig 5.9 and it goes straight to chapter review right after the code w/o any explanation. Nonetheless, i am loving the book so far.
My mistake on page number (was looking at a PDF). The comment is on page 189, as a snippet of the code was given there before presenting the full program on pages 191-192. I've edited the number above

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.