0

I do not understand why my 'old' list changes even though they do not share the same ID. I have not been able to find out, when I debug, I see the old list change, but cannot find a way around this. Found that creating a new list with a slice should change the ID of the two, but alas, here I am.

The only part of the code that actually uses the old list, is when I use .format.(old[i]), any help is appreciated.

menu = [
    ["egg", "bacon"],
    ["egg", "sausage", "bacon"],
    ["egg", "spam"],
    ["egg", "bacon", "spam"],
    ["egg", "bacon", "sausage", "spam"],
    ["spam", "bacon", "sausage", "spam"],
    ["spam", "sausage", "spam", "bacon", "spam", "tomato", "spam"],
    ["spam", "egg", "spam", "spam", "bacon", "spam"],
]

old = list(menu)

for i in range(len(menu))[::-1]:
    if "spam" in menu[i]:
        for k in range(len(menu[i]))[::-1]:
            if "spam" == menu[i][k]:
                del menu[i][k:k+1]

for i, meal in enumerate(menu):
    print("-"*80)
    print("{} contains, without spam:\n".format(old[i]))
    for part in meal:
        print(part)
else:
    print("-"*80)

Small shoutout to a Python Masterclass, and Monty Python...

  • Because `old = list(menu)` creates a *shallow copy*. That is, it creates *a new list* that contains *the same objecs* as the old list. So of course, when you mutate that object, that change is reflected in both lists. – juanpa.arrivillaga Sep 24 '20 at 00:38
  • Note, you *can* use `copy.deepcopy` for this, but if you know the structure, you can do it more efficiently doing `old = [x.copy() for x in menu]` – juanpa.arrivillaga Sep 24 '20 at 00:39
  • You can print the memory addresses of the objects: `print(id(menu), id(old))`. You will see they are the same object. – Mike67 Sep 24 '20 at 00:40
  • `list()` only converts data when needed, but `menu` is a `list` so nothing happens and `list(menu)` returns `menu` – rioV8 Sep 24 '20 at 00:41
  • 1
    @rioV8, incorrect - `list()` *always* returns a new list, even if passed a list. The optimization of returning the existing object if no conversion is required can only be safely applied to immutable objects. – jasonharper Sep 24 '20 at 01:25
  • @jasonharper So `list(foo)` === `[e for e in foo]`. list always traverses the iterable?? – rioV8 Sep 24 '20 at 01:31
  • @rioV8 absolutely incorrect. `list(menu) is not menu`. Try it yourself – juanpa.arrivillaga Sep 24 '20 at 01:43
  • @Mike67 no, they are not. – juanpa.arrivillaga Sep 24 '20 at 01:43
  • @rioV8 yes. Of course. – juanpa.arrivillaga Sep 24 '20 at 01:44
  • Thanks alot for the replies, honestly didn't expect anything as this is my very first post, so thank you! I like the solution provided by juanpa.arrivillaga, works like a charm. – MHB_2001 Sep 24 '20 at 08:27

0 Answers0