Variable Scope 2 -- Thanks for 1.

J

Jens Thiede

I found the querk in my code:

a = [1, 2, 3];
b = a;
b.append(4);

b == [1, 2, 3, 4]; # As it should.
a == [1, 2, 3, 4]; # - Why?

One would think that b is a referance to a - however I know it's not.
Without changing a thing from above, the following is true:

b = [];
b.append(5);
a == [1, 2, 3, 4];
b == [5];

How do I avoid accedentaly modifying variables, is this a bug? If not
why not?

Jens Thiede.

By the way, living in South Africa, where we have 11 national
languages is nice although - as a result - the World does not know
what to think of us. :)
 
J

JCM

Jens Thiede said:
I found the querk in my code:
a = [1, 2, 3];
b = a;
b.append(4);
b == [1, 2, 3, 4]; # As it should.
a == [1, 2, 3, 4]; # - Why?
One would think that b is a referance to a - however I know it's not.

Rather, a and b hold references to the same object--the list created
by the expression [1, 2, 3].
Without changing a thing from above, the following is true:
b = [];
b.append(5);
a == [1, 2, 3, 4];
b == [5];
How do I avoid accedentaly modifying variables, is this a bug? If not
why not?

Assignment rebinds variables to different objects, so b now holds a
reference to the list created by the expression [].
 
I

Irmen de Jong

Jens said:
I found the querk in my code:

a = [1, 2, 3];
b = a;
b.append(4);

First: please remove the ; from the end of your lines...

b == [1, 2, 3, 4]; # As it should.
a == [1, 2, 3, 4]; # - Why?

One would think that b is a referance to a - however I know it's not.

It's not. a and b are both a name (or a reference to) the same
list object [1,2,3]. (notice the subtle difference !)

Without changing a thing from above, the following is true:

b = [];
b.append(5);
a == [1, 2, 3, 4];
b == [5];

How do I avoid accedentaly modifying variables, is this a bug? If not
why not?

It's not a bug. It's the way Python works :)

A very important concept with Python is that you don't have variable
assignment, but name binding. An "assignment statement" binds a name on an
object, and the object can be of any type. A statement like this:

age = 29

doesn't assign the value 29 to the variable age. Rather, it labels the integer
object 29 with the name age. The exact same object can be given many names,
that is, many different "variables" can refer to the same value object:

firstName = login = recordName = "phil"

All three names now refer to the same string object "phil". Because assignment
in Python works this way, there are also no (type)declarations. You can
introduce a new name when you want, where you want, and attach it to any
object (of any type), and attach it to another object (of any type) when you
feel like it. For instance, if the line above has been executed and we then do

login=20030405

the name login now refers to an int object 20030405, while firstName and
recordName still refer to the old string "phil".

That's why b in your second example, is changed. b becomes a name for
a different list object (namely, the empty list []). a still refers to
the original list.

HTH,
--Irmen.
 
J

JCM

Irmen de Jong said:
A very important concept with Python is that you don't have variable
assignment, but name binding. An "assignment statement" binds a name on an
object, and the object can be of any type. A statement like this:
doesn't assign the value 29 to the variable age. Rather, it labels the integer
object 29 with the name age.

I think this statement is misleading--it seems to imply the integer
object is altered somehow. Personally I see no problem with saying
the value 29 is assigned to the variable age, so long as you
understand the semantics.
 
D

Duncan Booth

I think this statement is misleading--it seems to imply the integer
object is altered somehow. Personally I see no problem with saying
the value 29 is assigned to the variable age, so long as you
understand the semantics.

Be careful. The integer object is actually altered, at least in so far as
its reference count (which is part of the object) is changed:
 
S

Shalabh Chaturvedi

Duncan said:
Be careful. The integer object is actually altered, at least in so far as
its reference count (which is part of the object) is changed:

Off the orig topic, but I think this only happens for small numbers
(optimization - only one object exists for small numbers in Python).

In other words:
False

Of course, 'is' isn't useful when comparing int objects. For other
operations, the semantics are not affected anyway as int objects are
immutable.
 
J

Jens Thiede

OK, thanks for sorting that out, but what do I replace in the
following to avoid referancing:

x = [[0]*5]*5
x is [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]

and after

x[0][0] = 1;
x is [[1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0]]

is there a shorthand way to avoid referance or do I have to use a loop
or:

x = [[0]*5]+[[0]*5]+[[0]*5]+[[0]*5]+[[0]*5]

which is obviously stupid to try and do when the second cofficiant is
large or a variable.

Help would be much appreciated,

Jens Thiede
 
P

Peter Otten

Jens said:
OK, thanks for sorting that out, but what do I replace in the
following to avoid referancing:

x = [[0]*5]*5
x is [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]

and after

x[0][0] = 1;
x is [[1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0]]

is there a shorthand way to avoid referance or do I have to use a loop
or:

x = [[0]*5]+[[0]*5]+[[0]*5]+[[0]*5]+[[0]*5]

which is obviously stupid to try and do when the second cofficiant is
large or a variable.
x = [[0]*5 for i in range(5)]
x[0][0] = 1
x
[[1, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0,
0, 0, 0]]

or
y = map(list, [[0]*5]*5)
y[0][0] = 1
y
[[1, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0,
0, 0, 0]]
Peter
 
F

Francis Avila

Jens Thiede wrote in message ...
OK, thanks for sorting that out, but what do I replace in the
following to avoid referancing:

x = [[0]*5]*5
x is [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]

and after

x[0][0] = 1;
x is [[1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0]]

Ah, the joy of list comprehensions!
x = [ [ 0 for i in range(5)] for j in range(5)]
x
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0,
0, 0, 0]]
[[1, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0,
0, 0, 0]]
There are other ways, but using list comprehensions is the usual idiom now.
 
F

Francis Avila

Francis Avila wrote in message said:
Jens Thiede wrote in message ...
OK, thanks for sorting that out, but what do I replace in the
following to avoid referancing:

x = [[0]*5]*5
x is [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]

and after

x[0][0] = 1;
x is [[1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0]]

Ah, the joy of list comprehensions!
x = [ [ 0 for i in range(5)] for j in range(5)]

In my enthusiasm for list comprehensions I went too far. The inner loop
comp is unnecessary because ints are immutable. So [ [0]*5 for i in
range(5) ] is enough.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,175
Messages
2,570,942
Members
47,491
Latest member
mohitk

Latest Threads

Top