2

I have the following problem which I would like to illustrate by showing the following two minimal classes first before I explain in detail:

class Example1:

    def __init__(self):
        pass

    def function11(self,x):
        x=2*x+1
        return x

    def function12(self,x):
        y=0
        z=x
        while y<z:
            x=self.function11(x)
            y=y+1
        return x

class Example2:# the only difference to the previous class: it handles 
               #lists instead of numbers

    def __init__(self):
        pass

    def function21(self,x):
        x[0]=2*x[0]+1
    return x

    def function22(self,x):
        y=0
        z=x[0]
        while y<z:
            x=self.function21(x)
            y=y+1
        return x    



if __name__=="__main__":
    A1=Example1()
    x1=A1.function11(3)
    y1=A1.function12(x1)
    print'Result of Example1:'
    print x1
    print y1
    print 

    A2=Example2()
    x2=A2.function21([3])
    y2=A2.function22(x2)
    print'Result of Example2:'
    print x2
    print y2

And here is the output:

Result of Example1:
7
1023

Result of Example2:
[1023]
[1023]
>>>

What I don't understand here: why is the variable x2 overwritten with the value of y2? It obviously depends on the fact that lists are mutable objects in Python, am I right? My search on this led me to an article by Effbot. Still, I don't really understand what's going on here.

Martin Monath
  • 117
  • 1
  • 1
  • 7
  • Because, in `Example2.function21` you are passing around a list object and mutating it through its indices (in `x[0]=2*x[0]+1`). In `Example1.function11` you are are not mutating the original variable (just reassigning the name to a different object through: `x=2*x+1`) – UltraInstinct Mar 15 '17 at 17:36
  • Reading [this answer](http://stackoverflow.com/questions/23852480/assigning-value-in-python-dict-copy-vs-reference) might help – holdenweb Mar 15 '17 at 17:41

2 Answers2

1

function12 and function12 do not mutate their input parameter (which, by the way, is impossible anyway for immutable types such as int). They just compute a result based on the argument, rebind the name x to the value of that computation and then return that result.

function21 and function22 mutate their input parameter and then return it.

That's really all there is to it. Here's a shorter demonstration of functions with and without sideeffects on their input arguments:

>>> def no_sideeffects(x):
...     return x + [1] # build a new list and return the result, don't touch x
... 
>>> x = [0]
>>> no_sideeffects(x)
[0, 1]
>>> x
[0]
>>> 
>>> def sideeffects(x):
...     x[0] = 23 # mutate x, i.e. change value at index 0
...     return x # then return it
... 
>>> x
[0]
>>> sideeffects(x)
[23]
>>> x
[23]
timgeb
  • 76,762
  • 20
  • 123
  • 145
0

The difference between Example1 and Example2 is that you are returning a value in Example1, but a list in Example2.
Example2 returns the same list that was passed to it, and so, when you call function22, you are re-using the same list, and hence, it's value gets overwritten.

Priyank
  • 1,513
  • 1
  • 18
  • 36