Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this Python snippet regarding dictionaries work? [duplicate]

Say we have this

>>> x = {'a': 1, 'b': 2}
>>> y = {}
>>> for k, y[k] in x.items(): pass
...
>>> y
{'a': 1, 'b': 2}

Why does this work?

Note: I saw this first here

like image 810
asdrubalivan Avatar asked Oct 22 '21 18:10

asdrubalivan


People also ask

Is dictionary duplicate in Python?

The straight answer is NO. You can not have duplicate keys in a dictionary in Python.

Which statement creates a duplicate copy of a dictionary?

The dict. copy() method returns a shallow copy of the dictionary. The dictionary can also be copied using the = operator, which points to the same object as the original. So if any change is made in the copied dictionary will also reflect in the original dictionary.

Do dictionaries allow duplicate keys?

The Key value of a Dictionary is unique and doesn't let you add a duplicate key entry.

Which one of the following Python functions removes duplicates from a dictionary?

We can use loop or dictionary comprehension to remove duplicates from the dictionary in Python. While removing a duplicate value from the dictionary the keys are also removed in the process. If you don't care about retaining the original order then set(my_list) will remove all duplicates.


3 Answers

a, b = (c, d) unpacks the tuple from left to right and assigns a = c and b = d in that order.

x.items() iterates over key-value pairs in x. E.g. doing list(x.items()) will give [('a', 1), ('b', 2)]

for a, b in x.items() assigns the key to a, and the value to b for each key-value pair in x.

for k, y[k] in x.items() assigns the key to k, and the value to y[k] for each key-value pair in x.

You can use k in y[k] because k has already been assigned since unpacking happens left-right

You don't need to do anything in the loop because whatever you needed is done already.

Because the loop already assigned every value in x to y[k], y is now a shallow copy of x.

As the tweet you reference says, this is indeed a "terse, unintuitive, and confusing" way to do x.copy()

like image 81
Pranav Hosangadi Avatar answered Oct 18 '22 22:10

Pranav Hosangadi


This is a remarkably odd way to use the loop binding. For each item, the tuple of (key, value) is assigned into k, y[k]. Both instances of k refer to the same variable, so the subscription y[k] assigns into the dictionary y. This relies on a destructuring assignment being solved left to right; using y[k], k doesn't work as k isn't assigned the first time through the loop.

like image 3
Yann Vernier Avatar answered Oct 18 '22 23:10

Yann Vernier


The iterating variable is assigned values as it iterates through the iterable. In your case, k, y[k] are assigned with (key, value) from dict.items().

In your case y[k] actually calls dict.__setitem__ here which is why your y gets updated.

Example,

class T():
    def __setitem__(self, key, value):
        print(f"Assigning {key} with value {value}")


x = {"a": 2, "b": 3, "c": 4}
val = T() 

for k, val[k] in x.items():
    pass

Assigning a with value 2
Assigning b with value 3
Assigning c with value 4

In your case dict.__setitem__ is called while iterating through x.items() and dict.__setitem__ mutates your dict y so eventually you are copying x dict into y.


As an aside: I have one more "obnoxious, unintuitive, and confusing" way to copy a dict.
x  = {'a': 2, 'b': 3, 'c': 4}
it = iter(x.items())
y  = {}
[*iter(lambda : y.__setitem__(*next(it)), "Is this confusing enough??")]
print(y)
# {'a': 2, 'b': 3, 'c': 4}
like image 2
Ch3steR Avatar answered Oct 18 '22 23:10

Ch3steR