2
#!/usr/bin/env python

def modify_dict():

    d['two'] = 2

d = {'one':1}

modify_dict()

print d

I get

$ ./globaltest.py 
{'two': 2, 'one': 1}

I was hoping to see only {'one':1} since d is not declared global within the function. Why did d get both key-value pairs ?

Ankur Agarwal
  • 23,692
  • 41
  • 137
  • 208
  • 2
    Because `d` is mutable and the operation you performed on `d` inside dictionary is not be considered as an assignment operation by functions. For example with lists(mutable object) `+=` operator will raise error in function body, but .append and .extend and assignment by index will work fine. – Ashwini Chaudhary Sep 18 '14 at 06:07
  • 2
    To expand - when you assign (`x = y`) to a variable inside a function, python implicitly decides you're referring to a local. The syntax `d[k] = x` resolves to a `__setitem__` call - so while it looks syntactically like assignment, it is not. – roippi Sep 18 '14 at 06:20
  • Does this answer your question? [Why is the global keyword not required in this case?](https://stackoverflow.com/questions/14081308/why-is-the-global-keyword-not-required-in-this-case) – user202729 Feb 22 '21 at 03:19

3 Answers3

3

Python search for variables is based on the LEGB rule:

Local, Enclosing functions, Global, Built-in

When you call your function it tries to find a variable named d, and will find in global scope since you created d before calling the function. And since d is mutable, it will get updated.

lucasmullerm
  • 163
  • 6
3

Take a look at the data model of python. Dictionaries and lists are mutable objects, which is why globally defined dictionaries for example do not need to be declared global. Their contents may be changed at any time.

To understand mutability, think of the strings in python. They are an immutable object. You can for example replace the contents of a given string but in doing so the interpreter creates a new string object, and thus gives this string object a new identity (and thus a memory address).

>>> s = "foo"
>>> id(s)
140202745404072
>>> s = "bar"
>>> id(s)
140202745404112

I've answered a few similar questions before, so take a look if you can find more information from them.

Community
  • 1
  • 1
msvalkon
  • 11,887
  • 2
  • 42
  • 38
2

In a quick workaround is copy dictionary in local scope of the function.

import copy

d = {'one':1}

def modify_dict():
    local_d = copy.deepcopy(d)
    local_d['two'] = 2
    print local_d

modify_dict()
print d

you will see output following :

>>>{'two': 2, 'one': 1}
>>>{'one': 1}
Shawn Zhang
  • 1,680
  • 1
  • 12
  • 21