FAQ

[Python] Variable Scope 2 -- Thanks for 1.

Jens Thiede
Jan 9, 2004 at 8:47 pm
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. :)
reply

Search Discussions

11 responses

  • JCM at Jan 9, 2004 at 8:56 pm

    Jens Thiede wrote:
    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 [].
  • Ian at Jan 9, 2004 at 9:03 pm

    On Fri, 09 Jan 2004 20:56:26 +0000, JCM wrote:
    Assignment rebinds variables to different objects, so b now holds a
    reference to the list created by the expression [].
    As assignment binds but doesn't copy, you might ask

    http://www.python.org/doc/faq/programming.html#how-do-i-copy-an-object-in-python

    --IAN

  • Notice: Undefined variable: pl_u_link_beg in /home/whirl/sites/grokbase/root/www/public_html__www/cc/flow/tpc.php on line 831
    Irmen de Jong
    Notice: Undefined variable: pl_u_link_end in /home/whirl/sites/grokbase/root/www/public_html__www/cc/flow/tpc.php on line 831
    at Jan 9, 2004 at 9:01 pm

    Jens Thiede wrote:

    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 030405

    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.
  • JCM at Jan 9, 2004 at 9:32 pm
    Irmen de Jong wrote:
    ...
    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.
    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.
  • Duncan Booth at Jan 10, 2004 at 12:14 pm
    JCM <joshway_without_spam at myway.com> wrote in
    news:btn6ks$ada$1 at fred.mathworks.com:
    Irmen de Jong wrote:
    ...
    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.
    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:
    import sys
    sys.getrefcount(29)
    11
    age = 29
    sys.getrefcount(29)
    12
    >>>

    --
    Duncan Booth duncan.booth at suttoncourtenay.org.uk
    int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
    "\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?
  • Shalabh Chaturvedi at Jan 11, 2004 at 3:05 am

    Duncan Booth wrote:

    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:
    import sys
    sys.getrefcount(29)
    11
    age = 29
    sys.getrefcount(29)
    12
    Off the orig topic, but I think this only happens for small numbers
    (optimization - only one object exists for small numbers in Python).
    a = 101
    sys.getrefcount(101)
    2
    b = 101
    sys.getrefcount(101)
    2
    >>>

    In other words:
    a = 29
    b = 29
    a is b
    True
    a = 101
    b = 101
    a is b
    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.

    --
    Shalabh
  • Francis Avila at Jan 9, 2004 at 9:09 pm
    Jens Thiede wrote in message ...
    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.
    Ordinarily I would write a big custom-made explaination complete with
    examples. However:

    http://starship.python.net/crew/mwh/hacks/objectthink.html

    This is good enough.

    --
    Francis Avila
  • Jens Thiede at Jan 11, 2004 at 6:45 pm
    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
  • Peter Otten at Jan 11, 2004 at 7:05 pm

    Jens Thiede wrote:

    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
  • Francis Avila at Jan 11, 2004 at 7:17 pm
    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]]
    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]]
    >>>

    There are other ways, but using list comprehensions is the usual idiom now.

    --
    Francis Avila
  • Francis Avila at Jan 11, 2004 at 7:20 pm
    Francis Avila wrote in message <10038cpbu23hv93 at corp.supernews.com>...
    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.

    --
    Francis Avila

Related Discussions