> > Guess the simple types show the expected behaviour (even though they are > technically instances of existing classes). The user defined classes seem to > be references/shallow copies.
I prefer to avoid the term "reference" when talking about Python semantics, because it tends to make a lot of people get very opinionated on "call-by-value", "call-by-preference", and such, and how they work in other languages and it doesn't quite match up to how things work in Python. In Python every assignment (be it x = y, def foo(): pass, and varieties) are bindings of Objects to Names. That's all: there's no copying going on ever. The only time Python copies an object is if you explicitly copy it. In this code: >>> p=55 >>> q=p An int object, 55, is bound to the name 'p' in the first line. In the second line, the object bound to 'p' (the int object 55) is bound to the name 'q' There's no copying going on. At the end of this, you have two names pointing to the same object. When you next execute the code: >>> q=44 You're binding a different object (the int 44) to the name 'q'. As you show, 'p' is not modified because p and q are not /variables/ really: they're names that point to objects. That you changed where one name points doesn't change where another name points. Things get interesting because Python has two kinds of types: immutable and mutable types. The code: >>> p = p + 5 Results in the object that 'p' points to being added to the object int 5, which results in an entirely new object being created (int 60), which is then bound to the name 'p' again. What looks like changing an int is not changing the actual int at all, but instead creating new objects and binding them to the name 'p'. That's because ints (like strings and tuples) are immutable. Any operation which might appear to change it /does not/ change it: it returns an entirely new object instead. >>> s = "Hello" >>> t = s.replace("o", "a") >>> s 'Hello' >>> t 'Hella' The str.replace operation doesn't change s, it returns a new string object that has the replace operation performed on it. You can bind the new object to the same name as the previous one (thus making the previous one be destroyed if no other names point to them) by >>> s = s.replace("o", "a") For immutable types, when you pass the objects into functions (thus binding the object to the name specified in the def() line), any changes to the binding within the def don't propagate outside the function context: because every change to the names inside the def are not changing the objects pointed to by the names outside: they're just rebinding the internal names. People get a confused because if you pass a mutable object inside a def function and mutate that object the changes /are/ propagated outside-- because now you have a name inside the function and a name outside the object both pointing to the same object. If you want a function to work on a copy of a mutable object passed to it, and not the real object itself, you must explicitly make a copy of it. This code: >>>class AA: a=111 >>> x=AA() >>> x.a 111 >>> y=x >>> y.a 111 >>> y.a=222 >>> x.a 222 is demonstrating something else entirely. A class is made with a name bound to the classes namespace, called 'a'. Then you're trying to access an instance's namespace to fetch the object pointed to by its 'a' name: but with instances, if they do not have a name of their own they will access their classes bindings instead. If you set an "a" onto an instance, it won't be seen on another instance because that instance's 'a' will shadow/override the classes binding. The reason you see the "undesirable" behavior of a change to y.a showing the same result of x.a... is because those are the *exact* same instance. You didn't make a copy of the instance, you just made a new name and bound it to the same instance. If you want to copy in Python you have to explicitly do so, via the 'copy' module or any copy methods an object provides. -breathe- Hope that helps. --S
-- http://mail.python.org/mailman/listinfo/python-list