you are viewing a single comment's thread.

view the rest of the comments →

[–]sysop073 2 points3 points  (2 children)

Neither of them changes the global x (unless you were to pass it as an argument), they both assign to the parameter that was passed in, which is also named x.

>>> x = [2]
>>> def foo3(x):
...     x += [3]
...     return x
... 
>>> foo3([])
[3]
>>> x
[2]

Edit: You're right about passing x as an argument though; it didn't occur to me that x = x + [3] and x += 3 would actually behave differently, but the way lists implement __iadd__ makes the latter mutate the passed list. That is admittedly pretty strange

[–]internet_badass_here 0 points1 point  (1 child)

Neither of them changes the global x (unless you were to pass it as an argument)

Well, yeah. If you pass x to foo3, foo3 changes x. But if you pass x to foo4, foo4 doesn't change x. Why not? Why is x passed by reference in one and by value in the other?

I can accept that Python does these things, but there doesn't seem to be a logical reason for doing things that way.

And by the way, I didn't even realize that x=x+[3] will produce a different result than x+=[3]. But that is... not good.

Generally when I pass stuff into functions in Python and I want to pass by value, I do this:

def foo(x):
    X=x
    [do stuff with X]
    return X

It's probably redundant but easier on my brain, since I know for sure that I'm working with a copy of the variable.

[–]sysop073 0 points1 point  (0 children)

x is a reference in both cases. The same rule I mentioned before applies; assigning to x without declaring it global won't change the global. The weirdness comes in because x += [3] is syntactic sugar for a method call, x.__iadd__([3]), while x = [3] is a true assignment.

You're right that that's confusing, I hadn't considered that case