I originally thought Python was a pure pass-by-reference language.
Coming from C/C++ I can\'t help but think about memory management, and it\'s hard to put it out of my
Python is not Java, nor C/C++ -- you need to stop thinking that way to really utilize the power of Python.
Python does not have pass-by-value, nor pass-by-reference, but instead uses pass-by-name (or pass-by-object) -- in other words, nearly everything is bound to a name that you can then use (the two obvious exceptions being tuple- and list-indexing).
When you do spam = "green"
, you have bound the name spam
to the string object "green"
; if you then do eggs = spam
you have not copied anything, you have not made reference pointers; you have simply bound another name, eggs
, to the same object ("green"
in this case). If you then bind spam
to something else (spam = 3.14159
) eggs
will still be bound to "green"
.
When a for-loop executes, it takes the name you give it, and binds it in turn to each object in the iterable while running the loop; when you call a function, it takes the names in the function header and binds them to the arguments passed; reassigning a name is actually rebinding a name (it can take a while to absorb this -- it did for me, anyway).
With for-loops utilizing lists, there are two basic ways to assign back to the list:
for i, item in enumerate(some_list):
some_list[i] = process(item)
or
new_list = []
for item in some_list:
new_list.append(process(item))
some_list[:] = new_list
Notice the [:]
on that last some_list
-- it is causing a mutation of some_list
's elements (setting the entire thing to new_list
's elements) instead of rebinding the name some_list
to new_list
. Is this important? It depends! If you have other names besides some_list
bound to the same list object, and you want them to see the updates, then you need to use the slicing method; if you don't, or if you do not want them to see the updates, then rebind -- some_list = new_list
.