what does 'a=b=c=[]' do

Discussion in 'Python' started by Eric, Dec 21, 2011.

  1. Eric

    Eric Guest

    Is it true that if I want to create an array or arbitrary size such
    as:
    for a in range(n):
    x.append(<some function...>)

    I must do this instead?
    x=[]
    for a in range(n):
    x.append(<some function...>)

    Now to my actual question. I need to do the above for multiple arrays
    (all the same, arbitrary size). So I do this:
    x=y=z=[]
    for a in range(n):
    x.append(<some function...>)
    y.append(<some other function...>)
    z.append(<yet another function...>)

    Except it seems that I didn't create three different arrays, I created
    one array that goes by three different names (i.e. x[], y[] and z[]
    all reference the same pile of numbers, no idea which pile).

    This surprises me, can someone tell me why it shouldn't? I figure if
    I want to create and initialize three scalars the just do "a=b=c=7",
    for example, so why not extend it to arrays. Also, is there a more
    pythonic way to do "x=[], y=[], z=[]"?

    It's a slick language but I still have trouble wrapping my brain
    around some of the concepts.

    TIA,
    eric
    Eric, Dec 21, 2011
    #1
    1. Advertising

  2. On Wed, 21 Dec 2011 14:25:17 -0800 (PST), Eric <>
    wrote:


    >Except it seems that I didn't create three different arrays, I created
    >one array that goes by three different names (i.e. x[], y[] and z[]
    >all reference the same pile of numbers, no idea which pile).
    >
    >This surprises me, can someone tell me why it shouldn't? I figure if
    >I want to create and initialize three scalars the just do "a=b=c=7",
    >for example, so why not extend it to arrays. Also, is there a more
    >pythonic way to do "x=[], y=[], z=[]"?
    >
    >It's a slick language but I still have trouble wrapping my brain
    >around some of the concepts.
    >

    The key one is that lists ([] defines a list, not an array) are
    "mutable". Your "7" is not mutable.

    a = b = c = 7
    does the same thing as
    a = b = c = []
    which is to define the names "a", "b", and "c", and connects the three
    names to the single object (integer 7 or new empty list).

    b = 8
    then /disconnects/ the name "b" from the object (empty list or integer
    7) and connects the name to an integer 8 object.

    b = [1, 2, 3]
    disconnects the name "b" from the object and connects it to a list
    object containing three elements.

    b.append("something")
    however is going "inside" the object to change what it contains -- the
    connection remains the same object however.

    >>> a,b,c=[[] for x in range(3)]
    >>> a.append(1)
    >>> b

    []
    >>> c

    []
    >>> a

    [1]
    >>>


    For the amount of typing, it's easier to just do a straight line
    tuple unpack

    >>> a,b,c = ([],[],[])
    >>> a.append(2)
    >>> a

    [2]
    >>> b

    []
    >>> c

    []
    >>>


    --
    Wulfraed Dennis Lee Bieber AF6VN
    HTTP://wlfraed.home.netcom.com/
    Dennis Lee Bieber, Dec 21, 2011
    #2
    1. Advertising

  3. On Wed, 21 Dec 2011 14:25:17 -0800, Eric wrote:

    > Is it true that if I want to create an array or arbitrary size such as:
    > for a in range(n):
    > x.append(<some function...>)


    x is not defined, so you will get a NameError unless by some lucky fluke
    something else has created x AND it happens to be a list. Either way, it
    is unlikely to do what you want.


    > I must do this instead?
    > x=[]
    > for a in range(n):
    > x.append(<some function...>)


    Yes, you should create your lists before trying to append to them.

    But you aren't forced to use a for-loop. You can use a list comprehension:

    x = [some_function(a) for a in range(n)]

    Notice that here you don't need x to pre-exist, because the list comp
    creates a brand new list, which then gets assigned directly to x.


    > Now to my actual question. I need to do the above for multiple arrays
    > (all the same, arbitrary size). So I do this:
    > x=y=z=[]


    This creates one empty list object, and gives it three names, x, y and z.
    Every time you append to the list, all three names see the same change,
    because they refer to a single list.

    [...]
    > Except it seems that I didn't create three different arrays, I created
    > one array that goes by three different names (i.e. x[], y[] and z[] all
    > reference the same pile of numbers, no idea which pile).


    Exactly.

    > This surprises me, can someone tell me why it shouldn't?


    Because that's the way Python works. Python is an object-oriented, name
    binding language. This is how OO name binding works: you have a single
    object, with three names bound to it. The above line is short-cut for:

    a = []
    b = a
    c = a

    Python does not make a copy of the list unless you specifically instruct
    it to.


    > I figure if I
    > want to create and initialize three scalars the just do "a=b=c=7",


    That creates a single integer object with value 7, and binds three names
    to it, *exactly* the same as the above.

    If you could modify int objects in place, like you can modify lists in
    place, you would see precisely the same effect. But ints are immutable:
    all operations on ints create new ints. Lists are mutable, and can be
    changed in place.

    > for
    > example, so why not extend it to arrays. Also, is there a more pythonic
    > way to do "x=[], y=[], z=[]"?


    Well that literally won't work, you can't separate them by commas.
    Newlines or semicolons will work.

    Or: x, y, z = [], [], []

    Either is pretty Pythonic.



    --
    Steven
    Steven D'Aprano, Dec 21, 2011
    #3
  4. On Wed, 21 Dec 2011 18:20:16 -0500, Dennis Lee Bieber wrote:

    > For the amount of typing, it's easier to just do a straight line
    > tuple unpack
    >
    >>>> a,b,c = ([],[],[])


    Note that tuples are created by the comma, not the round brackets (or
    parentheses for any Americans reading). So the round brackets there are
    strictly redundant:

    a, b, c = [], [], []

    The only times you need the brackets around a tuple is to control the
    precedence of operations, or for an empty tuple.


    --
    Steven
    Steven D'Aprano, Dec 21, 2011
    #4
  5. Eric

    alex23 Guest

    On Dec 22, 8:25 am, Eric <> wrote:
    > This surprises me, can someone tell me why it shouldn't?  I figure if
    > I want to create and initialize three scalars the just do "a=b=c=7",
    > for example, so why not extend it to arrays.


    The thing to remember is that everything is an object, and that it's
    better to think of variables as labels on an object.

    So: a=b=c=7 means that _one_ integer object with the value of 7 can be
    referenced using any of the labels a, b or c. x=y=z=[] means that
    _one_ empty list can be referenced using x, y or z.

    The difference is that the value of a number object _cannot be
    changed_ ('immutable') while a list can be modified to add or remove
    items ('mutable'). a=10 just reassigns the label a to an integer
    object of value 10. x.append("foo") _modifies_ the list referred to by
    x, which is the same list known as y & z.

    > Also, is there a more pythonic way to do "x=[], y=[], z=[]"?


    I'd say that _is_ the most pythonic way, it's very obvious in its
    intent (or would be with appropriate names). If it bothers you that
    much:

    def listgen(count, default=[]):
    for _ in xrange(count):
    yield default[:]

    x, y, z = listgen(3)
    alex23, Dec 22, 2011
    #5
  6. Eric

    Rolf Camps Guest

    alex23 schreef op wo 21-12-2011 om 16:50 [-0800]:
    > On Dec 22, 8:25 am, Eric <> wrote:
    > > This surprises me, can someone tell me why it shouldn't? I figure if
    > > I want to create and initialize three scalars the just do "a=b=c=7",
    > > for example, so why not extend it to arrays.

    >
    > The thing to remember is that everything is an object, and that it's
    > better to think of variables as labels on an object.
    >
    > So: a=b=c=7 means that _one_ integer object with the value of 7 can be
    > referenced using any of the labels a, b or c. x=y=z=[] means that
    > _one_ empty list can be referenced using x, y or z.
    >
    > The difference is that the value of a number object _cannot be
    > changed_ ('immutable') while a list can be modified to add or remove
    > items ('mutable'). a=10 just reassigns the label a to an integer
    > object of value 10. x.append("foo") _modifies_ the list referred to by
    > x, which is the same list known as y & z.
    >
    > > Also, is there a more pythonic way to do "x=[], y=[], z=[]"?

    >
    > I'd say that _is_ the most pythonic way, it's very obvious in its
    > intent (or would be with appropriate names). If it bothers you that
    > much:
    >
    > def listgen(count, default=[]):
    > for _ in xrange(count):
    > yield default[:]
    >
    > x, y, z = listgen(3)
    >



    I'm afraid it's dangerous to encourage the use of '[]' as assignment to
    a parameter in a function definition. If you use the function several
    times 'default' always points to the same list.

    >>> def return_list(list_ = []):
    >>> return list_
    >>> a_list = return_list()
    >>> a_list

    []
    >>> a_list.append(3)
    >>> a_list

    [3]
    >>> b_list = return_list()
    >>> b_list
    >>> [3] # !!??


    >>> def return_list():
    >>> return []
    >>> a_list = return_list()
    >>> a_list

    []
    >>> a_list.append(3)
    >>> a_list

    [3]
    >>> b_list = return_list()
    >>> b_list
    >>> [] # OK!


    I only use python3 so I don't know how these things work in other
    versions.

    No problem in your function since you yield a copy, but I've already
    seen long threads about this.

    I would change your function to (Python3.x):

    def empty_lists(count):
    for _ in range(count):
    yield []


    Regards,

    Rolf
    Rolf Camps, Dec 22, 2011
    #6
  7. Eric

    Ethan Furman Guest

    Rolf Camps wrote:
    > alex23 schreef op wo 21-12-2011 om 16:50 [-0800]:
    >> I'd say that _is_ the most pythonic way, it's very obvious in its
    >> intent (or would be with appropriate names). If it bothers you that
    >> much:
    >>
    >> def listgen(count, default=[]):
    >> for _ in xrange(count):
    >> yield default[:]
    >>
    >> x, y, z = listgen(3)
    >>

    > I would change your function to (Python3.x):
    >
    > def empty_lists(count):
    > for _ in range(count):
    > yield []


    While it's good to be careful, default mutable arguments have their
    place. Alex's versioun allows one to use an already existing list and
    get shallow copies of it, yours will only create empty lists.

    a, b, c = listgen([1, 2, 3])
    # a, b, & c are bound to different lists

    ~Ethan~
    Ethan Furman, Dec 22, 2011
    #7
  8. Eric

    alex23 Guest

    On Dec 22, 6:51 pm, Rolf Camps <> wrote:
    > I'm afraid it's dangerous to encourage the use of '[]' as assignment to
    > a parameter in a function definition. If you use the function several
    > times 'default' always points to the same list.


    I appreciate the concern, but adding a default argument guard would
    not only obscure the code. It's irrelevant, as you recognise, because
    no matter what, it's going to make copies of the default argument.

    You know what the say about foolish consistencies :)
    alex23, Dec 23, 2011
    #8
  9. Eric

    Ian Kelly Guest

    On Thu, Dec 22, 2011 at 7:10 PM, alex23 <> wrote:
    > On Dec 22, 6:51 pm, Rolf Camps <> wrote:
    >> I'm afraid it's dangerous to encourage the use of '[]' as assignment to
    >> a parameter in a function definition. If you use the function several
    >> times 'default' always points to the same list.

    >
    > I appreciate the concern, but adding a default argument guard would
    > not only obscure the code. It's irrelevant, as you recognise, because
    > no matter what, it's going to make copies of the default argument.


    It's only irrelevant in the immediate context of the code you posted.
    But when Joe Novice sees your code and likes it and duplicates it a
    million times without receiving any warning about it, he's eventually
    going to write a function that modifies its default list argument, and
    he'll be in for a nasty surprise when he does.
    Ian Kelly, Dec 23, 2011
    #9
  10. Eric

    alex23 Guest

    On Dec 23, 12:59 pm, Ian Kelly <> wrote:
    > It's only irrelevant in the immediate context of the code you posted.
    > But when Joe Novice sees your code and likes it and duplicates it a
    > million times


    I'm sorry, but I'm not going to modify my coding style for the sake of
    bad programmers.

    The context is _important_. Why should I guard against default
    argument mutability when its not going to occur in the function body?
    alex23, Dec 23, 2011
    #10
  11. Eric

    Eric Guest

    On Dec 21, 6:50 pm, alex23 <> wrote:
    > On Dec 22, 8:25 am, Eric <> wrote:
    >
    > > This surprises me, can someone tell me why it shouldn't?  I figure if
    > > I want to create and initialize three scalars the just do "a=b=c=7",
    > > for example, so why not extend it to arrays.

    >
    > The thing to remember is that everything is an object, and that it's
    > better to think of variables as labels on an object.
    >
    > So: a=b=c=7 means that _one_ integer object with the value of 7 canbe
    > referenced using any of the labels a, b or c. x=y=z=[] means that
    > _one_ empty list can be referenced using x, y or z.
    >
    > The difference is that the value of a number object _cannot be
    > changed_ ('immutable') while a list can be modified to add or remove
    > items ('mutable'). a=10 just reassigns the label a to an integer
    > object of value 10. x.append("foo") _modifies_ the list referred to by
    > x, which is the same list known as y & z.
    >



    > > Also, is there a more pythonic way to do "x=[], y=[], z=[]"?

    >
    > I'd say that _is_ the most pythonic way, it's very obvious in its
    > intent (or would be with appropriate names). If it bothers you that
    > much:
    >


    Thanks for the explanation. I guess from what I've seen of Python
    so far I was expecting something more, I don't know, compact.
    Anyway, it doesn't bother me, at least not enough to go and do
    something like this:

    >     def listgen(count, default=[]):
    >         for _ in xrange(count):
    >             yield default[:]
    >
    >     x, y, z = listgen(3)


    Thanks,
    eric
    Eric, Dec 23, 2011
    #11
  12. On Fri, Dec 23, 2011 at 2:40 PM, alex23 <> wrote:
    > I'm sorry, but I'm not going to modify my coding style for the sake of
    > bad programmers.


    And there, folks, you have one of the eternal dilemmas. The correct
    decision depends on myriad factors; if you're writing code to go into
    the documentation as an example, you want it to be able to handle
    idiots hacking on it - but on the other hand, that same situation
    demands simplicity, which is why a lot of examples omit huge slabs of
    error checking.

    ChrisA
    Chris Angelico, Dec 23, 2011
    #12
  13. Eric

    Eric Guest

    On Dec 21, 5:44 pm, Steven D'Aprano <steve
    > wrote:

    > Yes, you should create your lists before trying to append to them.
    >
    > But you aren't forced to use a for-loop. You can use a list comprehension:
    >
    > x = [some_function(a) for a in range(n)]
    >
    > Notice that here you don't need x to pre-exist, because the list comp
    > creates a brand new list, which then gets assigned directly to x.
    >
    > > Now to my actual question.  I need to do the above for multiple arrays
    > > (all the same, arbitrary size).  So I do this:
    > >    x=y=z=[]

    >
    > This creates one empty list object, and gives it three names, x, y and z.
    > Every time you append to the list, all three names see the same change,
    > because they refer to a single list.
    >
    > [...]
    >
    > > Except it seems that I didn't create three different arrays, I created
    > > one array that goes by three different names (i.e. x[], y[] and z[] all
    > > reference the same pile of numbers, no idea which pile).

    >
    > Exactly.
    >
    > > This surprises me, can someone tell me why it shouldn't?

    >
    > Because that's the way Python works. Python is an object-oriented, name
    > binding language. This is how OO name binding works: you have a single
    > object, with three names bound to it. The above line is short-cut for:
    >
    > a = []
    > b = a
    > c = a
    >
    > Python does not make a copy of the list unless you specifically instruct
    > it to.
    >
    > > I figure if I
    > > want to create and initialize three scalars the just do "a=b=c=7",

    >
    > That creates a single integer object with value 7, and binds three names
    > to it, *exactly* the same as the above.
    >
    > If you could modify int objects in place, like you can modify lists in
    > place, you would see precisely the same effect. But ints are immutable:
    > all operations on ints create new ints. Lists are mutable, and can be
    > changed in place.
    >
    > > for
    > > example, so why not extend it to arrays.  Also, is there a more pythonic
    > > way to do "x=[], y=[], z=[]"?

    >
    > Well that literally won't work, you can't separate them by commas.
    > Newlines or semicolons will work.
    >
    > Or: x, y, z = [], [], []
    >
    > Either is pretty Pythonic.
    >
    > --
    > Steven


    Thanks to you and Dennis for the quick lesson and tips. Very helpful
    and illuminating.
    Eric, Dec 23, 2011
    #13
  14. Eric

    Ian Kelly Guest

    On Thu, Dec 22, 2011 at 8:40 PM, alex23 <> wrote:
    > On Dec 23, 12:59 pm, Ian Kelly <> wrote:
    >> It's only irrelevant in the immediate context of the code you posted.
    >> But when Joe Novice sees your code and likes it and duplicates it a
    >> million times

    >
    > I'm sorry, but I'm not going to modify my coding style for the sake of
    > bad programmers.


    Nobody is asking you to modify your coding style. The request is that
    you not throw it up as an example without mentioning the important
    caveats.

    Also, novice programmer == bad programmer?
    Ian Kelly, Dec 23, 2011
    #14
  15. Eric

    alex23 Guest

    On Dec 23, 3:22 pm, Ian Kelly <> wrote:
    > Nobody is asking you to modify your coding style.  The request is that
    > you not throw it up as an example without mentioning the important
    > caveats.


    No, 100% no. It's not my responsibility to mention every potentially
    relevant gotcha when providing example code.

    > Also, novice programmer == bad programmer?


    If they're wholly learning how to code by throwaway examples on
    mailing lists, then yes. Object mutability is a _major_ aspect of
    Python; I'm simply not going to inject an essay explaining what that
    implies every time I choose to use a mutable default argument.
    alex23, Dec 23, 2011
    #15
  16. Eric

    Ethan Furman Guest

    Ian Kelly wrote:
    > On Thu, Dec 22, 2011 at 7:10 PM, alex23 <> wrote:
    >> On Dec 22, 6:51 pm, Rolf Camps <> wrote:
    >>> I'm afraid it's dangerous to encourage the use of '[]' as assignment to
    >>> a parameter in a function definition. If you use the function several
    >>> times 'default' always points to the same list.

    >>
    >> I appreciate the concern, but adding a default argument guard would
    >> not only obscure the code. It's irrelevant, as you recognise, because
    >> no matter what, it's going to make copies of the default argument.

    >
    > It's only irrelevant in the immediate context of the code you posted.
    > But when Joe Novice sees your code and likes it and duplicates it a
    > million times without receiving any warning about it, he's eventually
    > going to write a function that modifies its default list argument, and
    > he'll be in for a nasty surprise when he does.


    And then he will learn about it and not make the mistake again (or if he
    does, it take much less time to figure it out).

    ~Ethan~
    Ethan Furman, Dec 23, 2011
    #16
  17. Eric

    rusi Guest

    On Dec 23, 7:10 am, alex23 <> wrote:
    > On Dec 22, 6:51 pm, Rolf Camps <> wrote:
    >
    > > I'm afraid it's dangerous to encourage the use of '[]' as assignment to
    > > a parameter in a function definition. If you use the function several
    > > times 'default' always points to the same list.

    >
    > I appreciate the concern, but adding a default argument guard would
    > not only obscure the code. It's irrelevant, as you recognise, because
    > no matter what, it's going to make copies of the default argument.
    >
    > You know what the say about foolish consistencies :)


    Programming languages can have bugs as much as programs can.
    A classic example is the precedence table of C which Kernighan or
    Ritchie (dont remember which) admitted was wrong.

    Likewise function arguments that default to mutable entities is a
    known gotcha of python which is best treated as a bug in python. It
    should be avoided with the suitable additional circumspection that a
    language bug deserves over a program bug.

    [Just my rephrasing of what Ian is saying]
    rusi, Dec 23, 2011
    #17
  18. Eric

    Ethan Furman Guest

    rusi wrote:
    > On Dec 23, 7:10 am, alex23 <> wrote:
    >> On Dec 22, 6:51 pm, Rolf Camps <> wrote:
    >>
    >>> I'm afraid it's dangerous to encourage the use of '[]' as assignment to
    >>> a parameter in a function definition. If you use the function several
    >>> times 'default' always points to the same list.

    >>
    >> I appreciate the concern, but adding a default argument guard would
    >> not only obscure the code. It's irrelevant, as you recognise, because
    >> no matter what, it's going to make copies of the default argument.
    >>
    >> You know what the say about foolish consistencies :)

    >
    > Programming languages can have bugs as much as programs can.
    > A classic example is the precedence table of C which Kernighan or
    > Ritchie (dont remember which) admitted was wrong.
    >
    > Likewise function arguments that default to mutable entities is a
    > known gotcha of python which is best treated as a bug in python. It
    > should be avoided with the suitable additional circumspection that a
    > language bug deserves over a program bug.


    That is the most ridiculous thing I have heard in a while. Mutable
    default arguments are *not* a bug in Python.

    Reminds me of a bug report a couple years back claiming multiple
    inheritence was a bug and asking it to be removed.

    ~Ethan~
    Ethan Furman, Dec 23, 2011
    #18
  19. On Fri, 23 Dec 2011 00:38:07 -0800, rusi wrote:

    > Likewise function arguments that default to mutable entities is a known
    > gotcha of python which is best treated as a bug in python.


    Nonsense. It is a feature, not a bug.

    Some people might argue that it is a mistake, a minor feature which
    allegedly causes more difficulties than benefits. I do not hold with that
    idea. But either way, it is not a bug to be fixed, but a deliberate
    consequence of intended semantics.



    --
    Steven
    Steven D'Aprano, Dec 23, 2011
    #19
  20. On Fri, Dec 23, 2011 at 7:49 PM, Ethan Furman <> wrote:
    > That is the most ridiculous thing I have heard in a while.  Mutable default
    > arguments are *not* a bug in Python.
    >
    > Reminds me of a bug report a couple years back claiming multiple inheritence
    > was a bug and asking it to be removed.


    Both of these could arguably be called misfeaures, but not bugs.

    ChrisA
    Chris Angelico, Dec 23, 2011
    #20
    1. Advertising

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.
Similar Threads
  1. Bill Johnson
    Replies:
    0
    Views:
    1,232
    Bill Johnson
    Jul 8, 2005
  2. Replies:
    3
    Views:
    480
    Ken Cox [Microsoft MVP]
    Oct 7, 2005
  3. Janet Collins
    Replies:
    0
    Views:
    1,144
    Janet Collins
    Jan 13, 2006
  4. Replies:
    1
    Views:
    840
    Juan T. Llibre
    Feb 8, 2006
  5. Alek Nazarian
    Replies:
    7
    Views:
    3,221
    Alek Nazarian
    Oct 22, 2003
Loading...

Share This Page