# scope, function, mutable

Discussion in 'Python' started by gusarer@gmail.com, Dec 4, 2012.

1. ### Guest

Hi,

What is the appropriate definition for the following behavior in Python 2.7
(see code below).
Both functions have assignment in it (like "x = ") so I assume, that x is a
local variable in both functions.
Also I thought this rule doesn't depend on WHERE in this function we find
the assignment.

But in both functions x becomes local variable only AFTER assignment, so in
f2 x[1] = 99 changes the global varialble (btw, x[3] = 99 doesn't).

def f1(x):
x = [44] + x[1:]
x[1] = 99

def f2(x):
x[1] = 99
x = [44] + x[1:]
x[3] = 99

t = [1,2,3,4,5,6,7]
f1(t)
print t # [1, 2, 3, 4, 5, 6, 7]
t = [1,2,3,4,5,6,7]
f2(t)
print t # [1, 99, 3, 4, 5, 6, 7]

Thank you.

Roman Gusarev.

, Dec 4, 2012

2. ### Steven D'ApranoGuest

On Tue, 04 Dec 2012 14:55:44 +0400, gusarer wrote:

> What is the appropriate definition for the following behavior in Python
> 2.7 (see code below).
> Both functions have assignment in it (like "x = ") so I assume, that x
> is a local variable in both functions.

Well, yes, but that's not why x is local in this case. In this case, x is
local because the name of the function parameter is "x", and function
parameters are always local.

> Also I thought this rule doesn't depend on WHERE in this function we
> find the assignment.
>
> But in both functions x becomes local variable only AFTER assignment,

Not so. Read on.

> so
> in f2 x[1] = 99 changes the global varialble (btw, x[3] = 99 doesn't).
>
> def f1(x):
> x = [44] + x[1:]
> x[1] = 99

When you call f1(t), with t a global list, Python passes the list object
to the function and binds it to name x. The function gets executed like
this pseudo-code:

# calling f1(t)
pass object known as "t" to the function
bind that object to the local name "x"
create a new list: [44] + a slice of x
bind this new list to name "x"
modify in place item 1 of the new list known as "x"

Notice that the only *modification* occurs after a new list is created
and bound to the name "x", so the modification does not change the
original, global, list.

But now consider your other function:

> def f2(x):
> x[1] = 99
> x = [44] + x[1:]
> x[3] = 99

In pseudo-code again:

# calling f2(t)
pass object known as "t" to the function
bind that object to the local name "x"
modify in place item 1 of the list known as "x",
which is another name for the global list known as "t"
create a new list: [44] + a slice of x
bind this new list to name "x"
modify in place item 3 of the new list known as "x"

So in this case you have to in-place modifications. The first occurs
while the name "x" still refers to the original list, and so it modifies
the original list. The second occurs after the name "x" has been rebound
to a new list, and so it doesn't change the original.

--
Steven

Steven D'Aprano, Dec 4, 2012

3. ### Jussi PiitulainenGuest

writes:

> What is the appropriate definition for the following behavior in
> Python 2.7 (see code below).
>
> Both functions have assignment in it (like "x = ") so I assume, that
> x is a local variable in both functions.

It's a local variable in both functions because it's a formal
parameter in both. The assignments don't make any difference
here. (And a statement like x[k] = ... never does.)

> Also I thought this rule doesn't depend on WHERE in this function we
> find the assignment.

That's correct but not relevant here. It's relevant when the variable
does not occur in the function's parameter list.

> But in both functions x becomes local variable only AFTER
> assignment, so in f2 x[1] = 99 changes the global varialble (btw,
> x[3] = 99 doesn't).

In both functions, x is local from the start. Its initial value is the
same mutable object that is the value of the global variable t. The
assignments x = [44] ... give it a new value, another mutable object,
but x[k] = ... don't. The latter make a change in the old value which
is still the value of the globale variable t.

> def f1(x):
> x = [44] + x[1:]
> x[1] = 99
>
> def f2(x):
> x[1] = 99
> x = [44] + x[1:]
> x[3] = 99
>
> t = [1,2,3,4,5,6,7]
> f1(t)
> print t # [1, 2, 3, 4, 5, 6, 7]
> t = [1,2,3,4,5,6,7]
> f2(t)
> print t # [1, 99, 3, 4, 5, 6, 7]

You might want to consider something like the following, because the
point really has everything to do with the fact that mutable objects
are not copied when they are passed to functions, assigned to
variables, or stored somewhere like a list, and little to do with
global vs local (other than there being different variables with the
same name).

t = [1,2,3]
u = [1,2,3]
w = u
w[1] = 0
u = t

Some people will tell you to use different words but the behaviour of
the language doesn't change.

Jussi Piitulainen, Dec 4, 2012

## Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.