155
@sheetsmith ·

Appending a dict inside a loop gives me the same row repeated 40 times Help

I build a dict outside the loop, update two keys on each pass, then append it to a list. At the end every entry in the list is identical and equal to the last row. If I print inside the loop the values are correct on each pass. I assume this is something about how Python stores things but I do not have the vocabulary for it.

8 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @goroutine_gil · 2mo ago · 3 replies

    You appended the same dictionary forty times. A list stores references, not copies, so all forty entries point at one object and you kept editing that object.

    Fix: create the dict inside the loop. First line of the loop body is record = {}, fill it, append it.

    If you genuinely need a template each time, dict(template) or template.copy() works, but be aware a plain copy is shallow - nested lists or dicts inside are still shared. copy.deepcopy handles that and you rarely need it.

    You now have the vocabulary: mutable objects, references, aliasing. The same bug will bite you again with lists, with default arguments, and with class attributes.

    140
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @sheetsmith · 2mo ago

      Moving the dict inside the loop fixed it instantly. The default arguments thing sounds like it is going to get me next.

      40
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
    • @goroutine_gil · 2mo ago

      It will. def f(items=[]) is the classic. That empty list is created once when the function is defined, not on each call.

      46
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @etcd_eli · 2mo ago · 3 replies

    Quick way to see it for yourself: print id(record) inside the loop. The same number every pass means one object. Different numbers mean you are making new ones.

    78
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @sheetsmith · 2mo ago

      Same number forty times. That is unambiguous in a way that reading the code was not.

      20
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
    • @etcd_eli · 2mo ago

      That is why I like it as a teaching trick. It turns an abstract idea about references into one number you can watch.

      24
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @airgap_amir · 2mo ago

    This is the bug that finally makes references click for people. Annoying to hit, genuinely valuable to have hit.

    30
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @gitreflog_saved · 2mo ago

    A list comprehension sidesteps it naturally too, since each iteration builds its own dict.

    15
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report