Michael Herrmann
Michael Herrmann

Reputation: 5003

Python: Changing value in imported dict has no effect

Here's a fun one. Create a file foo.py with the following contents:

OPTIONS = {'x': 0}

def get_option(key):
    from foo import OPTIONS
    return OPTIONS[key]

if __name__ == '__main__':
    OPTIONS['x'] = 1
    print("OPTIONS['x'] is %d" % OPTIONS['x'])
    print("get_option('x') is %d" % get_option('x'))

Running python foo.py gives the following output:

OPTIONS['x'] is 1
get_option('x') is 0

I would have expected the result to be 1 in both cases. Why is it 0 in the second case?

Upvotes: 1

Views: 82

Answers (1)

Akshay Pratap Singh
Akshay Pratap Singh

Reputation: 3327

You are getting this because from foo import OPTIONS line in get_options() function loads a new local OPTIONS variable in a memory whose value is {'x':0}. But if you remove/comment that line, then you got your expected result, this is because as OPTIONS variable in get_options() is now a global variable, not a local.

OPTIONS = {'x': 0}

def get_option(key):
    # from foo import OPTIONS
    return OPTIONS[key]

if __name__ == '__main__':
    OPTIONS['x'] = 1
    print("OPTIONS['x'] is %d" % OPTIONS['x'])
    print("get_option('x') is %d" % get_option('x'))

You can also debug that by using the id() function which returns the “identity” of an object during it's lifetime.

For that the debugging code is:

OPTIONS = {'x': 0}

def get_option(key):
    from foo import OPTIONS
    print("Id is %d in get_option" % id(OPTIONS))
    return OPTIONS[key]

if __name__ == '__main__':
    OPTIONS['x'] = 1
    print("Id is %d in main" % id(OPTIONS))
    print("OPTIONS['x'] is %d" % OPTIONS['x'])
    print("get_option('x') is %d" % get_option('x'))

Output:

Id is 140051744576688 in main
OPTIONS['x'] is 1
Id is 140051744604240 in get_option
get_option('x') is 0

Note: values of id's can be changed on your system.

Now, you can see the id's is different in both place, this means that there are two OPTIONS inside get_options() function one is __main__.OPTIONS and other one is foo.OPTIONS. But, if comment/remove line from foo import OPTIONS in get_options(), you get same id's at both places.

Upvotes: 2

Related Questions