0

I'm trying to run a program that goes something like this:

newlist = oldlist
for n in range(100):
    #run some stuff to try and improve oldlist over the 100 times its looped though randomized algorithm
    if oldlist better than newlist:
        newlist = oldlist
return newlist

What I want to accomplish is to constantly updating "newlist" if my program managed to improve on the oldlist that is being constantly modified for 100 times though randomized algorithm.

This concept works if I'm working with variables but not lists presumably because of the way Python assign names to lists while not actually copying the list. When the program returns the newlist it is still the newlist as defined by outside the for-loop.

In complete frustration I decided to just change the newlist as well, in the following way:

newlist = list(oldlist) #having to do this is already pretty weird tbh...
for n in range(100):
    #run some stuff to try and improve oldlist over the 100 times its looped though randomized algorithm
    if oldlist better than newlist:
        for index, item in enumerate(oldlist):
            newlist[index] = item
return newlist

But that's such a round-a-bout way of doing things and it makes me sad, any thoughts on this/better way to do this? Also what's the benefit that comes from assigning two names to the same list when I didnewlist = oldlist instead of just making a copy automatically?

Yeti1t3Y
  • 21
  • 5

1 Answers1

2

You can overwrite the contents of a list, mutating the original object, like this:

newlist[:] = oldlist

This will keep all references that still exist to newlist in place; the object itself stays the same, only the contents change:

>>> newlist = [1, 2, 3, 4]
>>> oldlist = [5, 6, 7]
>>> id(newlist)
59558408
>>> newlist[:] = oldlist
>>> newlist
[5, 6, 7]
>>> id(newlist) # still the same id
59558408

This has the benefit that when you pass the list to a function, the function can mutate that exact list like that:

>>> def test (lst):
        lst[:] = [1, 2, 3, 4, 5]
        # note that we’re not returning the list; instead we modify the list itself

>>> l = [9, 8, 7, 6]
>>> test(l)
>>> l
[1, 2, 3, 4, 5]

what's the benefit that comes from assigning two names to the same list when I did newlist = oldlist instead of just making a copy automatically?

It comes down to simplicity. When assinging something, you are always copying a reference to the underlying object; it happens when you call a function too. So imagine you would call a function that takes a list and you would automatically get a copy of the list. That would probably be very expensive, and it’s likely that you don’t need a copy in the first place. It also wouldn’t be clear whether that would mean you would get a deep copy, or just a flat copy. So by default, there are no copies, and you have to explicitely create a copy: “Explicit is better than implicit”.

poke
  • 369,085
  • 72
  • 557
  • 602
  • To the downvoter: If you think this is wrong because OP wants to copy the `oldlist`, then you have it backwards. OP wants to update the newlist with the items from oldlist, by mutating the list object `newlist` references. See the loop OP used as a comparison! – poke Jul 08 '15 at 07:07