Список Python ([]) и []
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)
Мне сказали, что list([]) == []
. Итак, почему этот код делает
oldChain = list(chain)
вместо oldChain = chain
Это то же самое, поэтому не имеет значения, как это сделать?
Ответы
Ответ 1
list(chain)
возвращает неглубокую копию chain
, она эквивалентна chain[:]
.
Если вы хотите получить мелкую копию списка, используйте list()
, он также иногда используется для получения всех значений из итератора.
Разница между y = list(x)
и y = x
:
Неглубокая копия:
>>> 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:
Обратите внимание, что если x
содержит изменяемые объекты, то просто list()
или [:]
недостаточно:
>>> x = [[1,2],[3,4]]
>>> y = list(x) #outer list is different
>>> x is y
False
Но внутренние объекты по-прежнему ссылаются на объекты в 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]])
Поскольку внешние списки отличаются друг от друга, модификация x не влияет на y и наоборот
>>> x.append('bar')
>>> x,y
([[1, 2, 'foo'], [3, 4], 'bar'], [[1, 2, 'foo'], [3, 4]])
Для этого используйте copy.deepcopy
.
Ответ 2
Верно, что list([])
функционально эквивалентен []
, создавая новый пустой список.
Но x = list(y)
не совпадает с x = y
. Формеры делают мелкую копию, а последняя создает новую ссылку на существующий список.
Обратите внимание, что list([])
неэффективен - он создает новый пустой список (делая []
), затем копирует его, в результате чего появляется еще один пустой список (делая list(...)
), затем освобождает исходный, список.
Ответ 3
oldchain = list(chain)
oldchain указывает на новый список, который не является цепочкой (не тот же объект), но имеет такое же содержимое.
* Как упоминалось в других ответах, это делает oldchain "мелкой копией" цепочки.
oldchain = chain
oldchain просто указывает на цепочку, оба указывают на тот же объект
Однако обратите внимание, что oldchain = []
и oldchain = list()
функционально одинаковы, поскольку оба создают пустой список. Это становится другим, когда задействованы другие ссылки (т.е. chain
).
Ответ 4
Если это помогает, вот объяснение, взятое непосредственно со страницы 189 книги (объектно-ориентированное программирование на Python), сразу же ниже представления части кода:
"Важная тонкость в нашем подходе видна в строке 52. Эта строка заставляет oldChain быть копией цепочки. Обратите внимание, что это совсем другая семантика из команды oldChain = chain, которая просто сделает идентификатор ссылки oldChain один и тот же базовый список. Необходимость в этой копии выглядит следующим образом: внутренний цикл for используется для повторного подсчета положения каждой внутренней точки цепочки один за другим. Мы хотим сделать все эти вычисления на основе когерентного состояния Если бы мы не сделали копию, мы столкнулись бы со следующей проблемой: настройка на вторую точку в цепочке зависит от положений первой и третьей точек. Предположим, что мы должны были выполнить эту настройку, а затем продолжить Следующим шагом будет рассчитать корректировку третьей точки, которая зависит от позиций второй и четвертой точек. Но теперь будет несоответствие между предыдущей позицией второй точки и ее обновленной позицией. использование предыдущее положение второй точки для согласованности. По этой причине мы вычисляем все силы, основанные на копии старой цепи".