Title: Strange behavior in changing nested dictionaries
Type: behavior Stage: resolved
Components: Versions: Python 3.8
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: jacob.underwood, steven.daprano
Priority: normal Keywords:

Created on 2020-05-16 05:02 by jacob.underwood, last changed 2020-05-16 06:40 by jacob.underwood. This issue is now closed.

Messages (3)
msg369008 - (view) Author: Jacob Underwood (jacob.underwood) Date: 2020-05-16 05:02
I was experimenting with nested dictionaries when I came across strange behavior that I can not figure out at all. The following function, at least for me, has some weird behavior. Originally, it was a bit longer, but somehow it achieved its intended purpose in a strange way, allowing me to cut off the rest of the correct code and to leave only the following with the code still continuing to work:

My original intention was to make a function that would use the provided keys (in the "keys" argument of the following function) in the form of a list to use all but the last key in the list to get to a nested dictionary within the provided dictionary arg. Then, using the last key in the list, set the key to the information provided. Finally, the function should have returned the full dictionary originally provided, but with the one change within one of the nested dictionaries of the provided dictionary.

def input_into_nested_dict(dictionary, keys, information):
    its = information
    cdip = dictionary
    for key in keys[:-1]:
            cdip = cdip[key]
    cdip[keys[-1]] = its
    return dictionary

So, an example dictionary of
m = {'a':{'b':{'c':{'d':30}}}}

An example list of
y = ['a','b','c','test']

Test of
n = input_into_nested_dict(m, y, 'hello')

The strange thing is, n now correctly has
{'a': {'b': {'c': {'d': 30, 'test': 'hello'}}}}
which does not correspond to what this weird cut off function should do, as it should only provide
{'d': 30, 'test': 'hello'}

Furthermore, somehow this changes the global m, the dictionary provided to the function, making it
{'a': {'b': {'c': {'d': 30, 'test': 'hello'}}}}

(The strange variable names are left over from my original code, though removing them as they are now unnecessary changes the behavior again, even though I am pretty sure it should not (?))

Same function without the beginning variables:

def b(dictionary, keys, information):
    for key in keys[:-1]:
            dictionary = dictionary[key]
    dictionary[keys[-1]] = information
    return dictionary

Now, when ran with the same m (reset back to the original dictionary before it was somehow changed), y, and an n of
n = b(m, y, 'hello')
The result is now that n gets the correct dictionary it should get
{'d': 30, 'test': 'hello'}

Though, somehow m changing also continues, with it again getting
{'a': {'b': {'c': {'d': 30, 'test': 'hello'}}}}

If this makes no sense, I'm sorry I am new to Python and am not really good really giving this kind of information

In addition to that, this is probably not even a bug at all and I am probably just missing something big? If true, I'm sorry about this post...

I do not know if this happens to just me, this originally happened in 3.7.7 but I tried upgrading and it continued in the most recent version (3.8.3)

Thank you!
msg369013 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-05-16 05:48
Hi Jacob, and welcome.

You said: "I was experimenting with nested dictionaries when I came across strange behavior that I can not figure out at all."

This is a bug tracker, for reporting bugs, not a help desk for asking how to figure out Python's behaviour. Python is 30 years old and what you are calling "strange" has exactly how Python has worked for all that time. Sorry to tell you, but it is your understanding that is lacking, not a bug in the language.

I can't really tell why you think it is "strange" -- I've been using Python for 20 years or so, and I'm not sure what you think is weird about this, it all seems perfectly natural to me. I'm having difficulty in seeing why you expect something different, sorry.

This bug tracker is not the right place to get into a long discussion about Python's behaviour. There are plenty of other places, like the Python-List mailing list, or StackOverflow, or Reddit's r/learnpython. But I *guess* that maybe you expect that when you call your function

    input_into_nested_dict(m, y, 'hello')

that the dict `m` is copied before being passed to the function? If that's what you think is happening, let me assure you that no it is not. Python never copies data structures unless you explicitly tell it to, and specifically assignment does not make copies either.

So when you say `cdip = dictionary`, that doesn't make a copy of the input dict, it is just a new name for the original global dict.

These may help you:

Good luck!
msg369016 - (view) Author: Jacob Underwood (jacob.underwood) Date: 2020-05-16 06:40
I know this post is closed, but I just wanted to say thank you for the reply and the help, and being so understanding of my many mistakes

Have a good day/night!!
Date User Action Args
2020-05-16 06:40:58jacob.underwoodsetmessages: + msg369016
2020-05-16 05:48:37steven.dapranosetstatus: open -> closed

nosy: + steven.daprano
messages: + msg369013

resolution: not a bug
stage: resolved
2020-05-16 05:02:29jacob.underwoodcreate