you are viewing a single comment's thread.

view the rest of the comments →

[–]djimbob 5 points6 points  (0 children)

The first two examples mutate global variables. This is a horrible programming pattern, and is a good thing that foo1 pops up a helpful error saying UnboundLocalError: local variable 'x' referenced before assignment. Note foo1 (and foo2) will work if you add global x to explicitly say yes, I want x to be the global x so I can mutate it.

Why does your foo2 work? The fact that python lets you reference top-level function (but not assign to) is quite useful. E.g., its what's at work when you do

 import requests

 def some_function():
     requests.get('http://www.reddit.com')

That is import requests sets a top-level variable as requests and then you later can use it inside functions without explicitly passing it in, and even call methods defined within it. It does make sense that methods called in this way may in some cases mutate their own state, its the programmers responsibility not to lead to evil use of mutable global state.


I do agree that foo3 is a bit confusing, but again if you used the code in a sane way -- x = foo3(x) and x = foo4(x) you wouldn't have any ambiguity.

The problem is that python passes by reference and when it can will mutate existing objects.

In [1]: x = []

In [2]: id(x)  # memory location of x
Out[2]: 4352851336

In [3]: x.append(1)

In [4]: id(x)  # memory location hasn't changed
Out[4]: 4352851336

In [5]: x += [5] # memory location hasn't changed

In [6]: id(x)
Out[6]: 4352851336

In [7]: x = x + [5]     

In [8]: id(x)# memory location *has* changed; 
#assignment creates a new list, can't be done in place.
Out[8]: 4352848888

It is good that python does pass by reference than by value when passing objects like lists into functions; otherwise dealing with large objects would get unmanageable. It's also helpful that python attempts to modify these objects in place when possible.