strange behavor....

Mark Wooding mdw at distorted.org.uk
Sat Nov 13 11:29:19 EST 2010


Tracubik <affdfsdfdsfsd at b.com> writes:

> >>> def change_integer(int_value):
> ...     int_value = 10
> ...     
> ... def change_list(list):
> ...     list[0] = 10

[...]

> why the integer value doesn't change while the list value do?

Because in the first case you changed a variable local to the function,
and that variable was lost when the function returned; and in the second
case, you modified the list value that was passed to the function.

> in Pascal i can choose the behavour of parametres, how this work on
> Python?

You must learn to distinguish two notions to understand how this works
in Python: the notions are /assigning a value to a variable/, and
/mutating a value/.  The former is what simple assignment `foo = ...'
does: it makes the variable store a different value.  Assigning a value
to a function argument /never/ affects the caller in Python.  It's
simply not possible to write a `swap' function in Python.  The latter
means that a value itself changes but the relevant variables continue to
store the same values.

Alas, Python is actually slightly confusing here, since the same
notation `=' sometimes means assignment and sometimes means mutation.
You can tell which is which by looking at the left hand side: if it's a
simple variable name, the variable is assigned a new value; if it's
something more complicated (e.g., indexing (`foo[0]'), or attribute
selection (`foo.bar') then some mutation is (probably) going to happen:
these kinds of assignment are translated into method calls, so what
actually happens is up to the object in question.  It gets worse:
compound assignment -- statements like `foo += ...' -- might either be
mutation or assignment.  What happens if the current value of `foo' has
the an appropriate method is that the method is called, and probably
mutates the value of foo; otherwise Python treats the statement as if it
had been `foo = foo + (...)'.

Returning, sort of, to the point: if you want to write a function which
causes side-effects on its caller, then you have[1] to do it by mutating
the caller's argument values.  So you could write an awful `swap'
function like

        def awful_swap(x, y):
          x[0], y[0] = y[0], x[0]

and then you have to call it as

        xx = [x]
        yy = [y]
        awful_swap(xx, yy)
        x = xx[0]
        y = yy[0]

but there's no good reason to actually do such a thing in Python when
you can write

        x, y = y, x

anyway.

In Pascal, one tends to use `var' parameters to work around the fact
that Pascal functions can only return a single value.  This is true in
Python too, but it isn't anywhere near as annoying because Python makes
it easy (a) to combine multiple values together into a tuple (`return x,
y, z') and (b) to pick tuples apart into their components again at the
other end (`a, b, c = some_function()').  If you have a number of values
which you find that you're combining and splitting apart repeatedly then
maybe you're better off putting them together in a class with some
appropriate operations.

[1] In general; if the called function happens to be lexically enclosed
    in its caller, then it can play with its caller's variables
    directly -- well, in Python 3, anyway.

-- [mdw]



More information about the Python-list mailing list