Multi-dimensional list initialization
88888 Dihedral
dihedral88888 at googlemail.com
Thu Nov 8 18:18:11 EST 2012
On Monday, November 5, 2012 3:07:12 PM UTC+8, Chris Rebert wrote:
> On Sun, Nov 4, 2012 at 10:27 PM, Demian Brecht <demianbrecht at gmail.com> wrote:
>
> > So, here I was thinking "oh, this is a nice, easy way to initialize a 4D matrix" (running 2.7.3, non-core libs not allowed):
>
> >
>
> > m = [[None] * 4] * 4
This is not clear in a name binding objective
programming language.
b=[1,2,3,4]*4
mb=[ b]*4
# check the behaviors and usages of reference copies
# and shadow value copies and deep-value copies
>
> >
>
> > The way to get what I was after was:
>
> >
>
> > m = [[None] * 4, [None] * 4, [None] * 4, [None * 4]]
>
> >
>
> > (Obviously, I could have just hardcoded the initialization, but I'm too lazy to type all that out ;))
>
> >
>
> > The behaviour I encountered seems a little contradictory to me.
>
> > [None] * 4 creates four distinct elements in a single array
>
> > while [[None] * 4] * 4 creates one distinct array of four distinct elements, with three references to it:
>
>
>
> Incorrect. In /both/ cases, the result is a list of length 4, whose
>
> elements are 4 (references to) the exact same object as the original
>
> list's element.
>
> Put simply, the list multiplication operator never copies objects; it
>
> just makes additional references to them.
>
>
>
> However, unlike a list object (as in your latter example), the object
>
> `None` is completely immutable (and what's more, a singleton value),
>
> so you just-so-happen *not to be able to* run into the same problem of
>
> mutating an object (assignment to an index of a list constitutes
>
> mutation of that list) that is referenced in multiple places, for you
>
> cannot mutate None in the first place!:
>
> >>> x = None
>
> >>> x.a = 42
>
> Traceback (most recent call last):
>
> File "<stdin>", line 1, in <module>
>
> AttributeError: 'NoneType' object has no attribute 'a'
>
> >>> # it doesn't overload any mutating operators:
>
> >>> type(None).__dict__.keys()
>
> ['__hash__', '__repr__', '__doc__']
>
> >>> # and it obviously has no instance variables,
>
> >>> # so, we can't modify it in any way whatsoever!
>
> (Lists, on the other hand, define item assignment, .pop(), .remove(),
>
> and a few other mutator methods.)
>
>
>
> >>>> a = [None] * 4
>
> >>>> a[0] = 'a'
>
> >>>> a
>
> > ['a', None, None, None]
>
> >
>
> >>>> m = [[None] * 4] * 4
>
> >>>> m[0][0] = 'm'
>
> >>>> m
>
> > [['m', None, None, None], ['m', None, None, None], ['m', None, None, None], ['m', None, None, None]]
>
> >
>
> > Is this expected behavior
>
>
>
> Yes. It's also a FAQ:
>
> http://docs.python.org/2/faq/programming.html#how-do-i-create-a-multidimensional-list
>
>
>
> > and if so, why?
>
>
>
> It's a general (albeit AFAIK unstated) principle that Python never
>
> copies objects unless you explicitly ask it to. You have encountered
>
> one example of this rule in action.
>
>
>
> > In my mind either result makes sense, but the inconsistency is what throws me off.
>
>
>
> It is perfectly consistent, once you understand what list
>
> multiplication actually does.
>
>
>
> Cheers,
>
> Chris
>
> --
>
> http://rebertia.com
More information about the Python-list
mailing list