Varibles -- copies and references

Stephen Hansen apt.shansen at gmail.com
Tue Feb 3 01:47:41 EST 2009


>
> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20090202/2e1ad015/attachment-0001.html>


More information about the Python-list mailing list