Multi-dimensional list initialization

88888 Dihedral dihedral88888 at googlemail.com
Fri Nov 9 00:18:11 CET 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