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 <demianbre...@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 -- http://mail.python.org/mailman/listinfo/python-list