1

Let's for example define a class and a function

class class1(object):
    """description of class"""
    pass

def fun2(x,y):
    x.test=1;
    return x.value+y

then define a class instance and run it as a local variable in the function

z=class1()
z.value=1
fun2(z,y=2)

However, if you try to run the code

z.test

a result 1 would be returned.

That was, though the attribute to x was done inside the fun2() locally, it extended to class instance x globally as well. This seemed to violate the first thing one learn about the python function, the argument stays local unless being defined nonlocal or global.

How could this happen? Why the attribute to class inside a function extend outside the function.

  • 1
    Your class is mutable much like a `list` or `dict` would be changed inside the function as well. – Axe319 Jan 20 '21 at 12:47
  • 1
    Here is a very good explanation on discuss.python. https://discuss.python.org/t/why-do-my-lists-get-modified-when-passed-to-a-function/5036 – Axe319 Jan 20 '21 at 12:54
  • 1
    If you want a more detailed explanation I can write an answer. but basically, calling a function with arguments is assigning those variables to the arguments. In your case it would be like `x = z` outside the function. The same assignment rules apply regardless of type. The reason a `str` or `int` appears to create a copy(it actually doesn't) is because they're immutable. – Axe319 Jan 20 '21 at 13:12
  • Please clarify your question. *Variables* are local, *objects* are not. Did you expect the instance to be copied into the function? – MisterMiyagi Jan 20 '21 at 13:12
  • Does this answer your question? [Are python variables pointers? or else what are they?](https://stackoverflow.com/questions/13530998/are-python-variables-pointers-or-else-what-are-they) – MisterMiyagi Jan 20 '21 at 13:14
  • @Axe319 Thank you. I didn't realize that a user defined class was mutable by default. It's clear now. – ShoutOutAndCalculate Jan 20 '21 at 13:26

1 Answers1

2

I have even stranger example:

def fun3(a):
    b=a
    b.append(3)
    
mya = [1]
fun3(mya)

print(mya)

[1, 3]
> 

I "copy" the array to a local variable and when I change it, the global one changes as well.

The problem is that the parameters are not passed by a value (basically as a copy of the values). In python they are passed by reference. In C terminology the function gets a pointer to the memory location. It's much faster that way.

Some languages will not let you to play with private attributes of an instance, but in Python it's your responsibility to make sure that does not happen. One other rule of OOP is that you should change the internal state of an instance just by calling its methods. But you change the value directly.

Python is very flexible and allows you to do even the bad things. But it does not push you.

I always argue to have always at least vague understanding of the underlaying structure of any higher level language (memory model, how the variables are passed etc.). There is another argument for having some C/C++ knowledge. Most of the higher level languages are written in them or at least are inspired by them. A C++ programmer would see clearly what is going on.

petrch
  • 1,807
  • 15
  • 19