On Fri, 11 Feb 2005, Matt Dimmic wrote:
> In Python, one bug that often bites me is this: > > (example A) > aList = [1,2,3] > for i in aList: > i += 1 > print aList > --> [1,2,3] > > This goes against my intuition, which is that aList == [2,3,4], probably > because so much in Python is passed by reference and not by value. Hi Matt, Yes. If we "unroll" the loop, we can better see what's going on: ### aList = [1, 2, 3] i = aList[0] i += 1 i = aList[1] i += 1 i = aList[2] i += 1 print aList ### This has the same meaning as Example A, and it should be clearer why the assignment to 'i' has no affect. 'i' is just a regular local variable, just like any other local variable. Assignment is not the same thing as value mutation; it's actually the same issue that we talked about earlier with the default argument thread. *grin* When I see something like: ### x = 42 y = x y = y + 1 ### My visual model of this is that variable names are "arrows" to values: -------------------------------------------------- x -----------> 42 ## x = 42 ---------------------------------------------------- x -----------> 42 ## y = x ^ / y -----------/ ---------------------------------------------------- x -----------> 42 ## y = y + 1 y -----------> 43 ---------------------------------------------------- That being said, we can do something here with a little indirection: ### >>> def box(x): ... """Put a mutable wrapper around the value x.""" ... return [x] ... >>> def unbox(boxedValue): ... """Grab the value in the box.""" ... return boxedValue[0] ... >>> def incr(boxedValue): ... """Increment the value in the box.""" ... boxedValue[0] += 1 ... >>> >>> >>> aList = [box(1), box(2), box(3)] >>> map(unbox, aList) [1, 2, 3] >>> for b in aList: ... incr(b) ... >>> map(unbox, aList) [2, 3, 4] ### This might be overkill, though. *grin* But this shows that, if we really needed to, we could "box" everything in some kind of mutable container. I don't recommend this for normal Python programming, though. > Of course I can always use range() or enumerate(): > > (example B) > aList = [1,2,3] > for i in range(len(aList)): > aList[i] += 1 > print aList > --> [4,5,6] > > But example A seems more elegant, if only it did what I wanted it to do. > :) So pardon my ignorance if the answer is obvious, but what is the > simplest way in Python to get a reference to an element in a list? Is it > really Example B? A variation of Example B, with enumerate(), is probably the most straightforward way to do in-place mutation on the list in Python: ### aList = [1, 2, 3] for i, x in enumerate(aList): aList[i] = x + 1 print aList ### There are languages that magically allow us to do mutation on a list without making it look like list mutation. Perl is one of those languages that adds magic syntactic sugar for doing in-place list stuff. But Python has no special mechanisms for doing this. The main issue that I think people are running against is that, in Python, numeric values are "immutable" --- they can't be changed. When we do things like addition: ### >>> x = 7 >>> x = x + 1 ### we are not changing the value of '7': we're just "re-aiming" or directing 'x' to the new value '8'. If you have more questions, please feel free to ask! _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor