Multi-dimensional list initialization

Ian Kelly ian.g.kelly at gmail.com
Thu Nov 8 00:39:55 CET 2012


On Wed, Nov 7, 2012 at 3:02 PM, Andrew Robinson
<andrew3 at r3dsolutions.com> wrote:
> Draw up some use cases for the multiplication operator (I'm calling on your
> experience, let's not trust mine, right?);  What are all the Typical ways
> people *Do* to use it now?
>
> If those use cases do not *primarily* center around *wanting* an effect
> explicitly caused by reference duplication -- then it may be better to
> abolish list multiplication all together; and rather, improve the list
> comprehensions to overcome the memory, clarity, and speed pitfalls in the
> most common case of initializing a list.

Why?  Just to get rid of an FAQ?

Here's one of the more interesting uses from my own code:

    values = zip(samples, times * num_groups)
    if len(values) < len(times) * num_groups:
        # raise an error

Converting that multiplication to a generator expression would look like this:

    values = zip(samples, (t for _ in range(num_groups) for t in times))

That's not particularly hairy, but I do assert that it is
substantially less readable, and more so because it loses the symmetry
with the following if condition.

The recipes in the itertools docs also include this example, which
notably depends on the list containing multiple references to the same
iterator:

def grouper(n, iterable, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

Replacing the list multiplication in that function with a list
comprehension would be awkward, as the obvious replacement of
[iter(iterable) for _ in range(n)] would produce different results.


> For example, in initialization use cases; often the variable of a for loop
> isn't needed and all the initializers have parameters which only need to be
> evaluated *once* (no side effects).
>
> Hence, there is an opportunity for speed and memory gains,while maintaining
> clarity and *consistency*.
>
> Some ideas of use cases:
> [ (0) in xrange(10) ]  # The function to create a tuple cache's the
> parameter '0', makes 10 (0)'s
> [ dict.__new__(dict) in xrange(10) ]  # dict.__new__, The dict parameter is
> cached -- makes 10 dicts.
> [ lambda x:(0) in xrange(10) ] # lambda caches (0), returns a *reference* to
> it multiple times.

How exactly do you propose to indicate to the compiler which parts of
the expressions are meant to be cached, and which are not?

>>> Bull.  Even in the last thread I noted the range() object produces
>>> special cases.
>>>  >>> range(0,5)[1]
>>> 1
>>>  >>> range(0,5)[1:3]
>>> range(1, 3)
>>
>> What's the special case here? What do you think is copied?
>>
>>
>> You take a slice of a range object, you get a new range object.
>
> You were'nt paying attention, OCCASIONALLY, get an integer, or a list.
>>>> range(3)[2]
> 2
>
> LOOOOK! That's not a range object, that's an integer.  Use Python 3.2 and
> try it.

Of course you got an integer.  You took an index of the range object,
not a slice.  The rule is that taking an index of a sequence returns
an element; taking a slice of a sequence returns a sub-sequence.  You
still have not shown any inconsistency here.

> Game programmers routinely use 2D lists to represent the screen layout;
> For example, they might use 'b' to represent a brick tile, and 'w' to
> represent a water tile.

In many cases it may be simpler to use a plain list of strings:

screen = [
    "sssss",
    "ssbss",
    "sbbbs",
    "bbbbb",
]

> py> x = [{}]*5
> py> x
> [{}, {}, {}, {}, {}]
>
> No, I showed what happed when you do {}*3;
> That *DOESN'T* work;  You aren't multiplying the dictionary, you are
> multiplying the LIST of dictionaries.  Very different things.
> You were complaining that my method doesn't multiply them -- well, gee --
> either mine DOES or python DOESN'T.  Double standards are *crap*.

No, he wasn't.  He was talking about multiplying lists of dicts, and
whether the dicts are then copied or not, just like every other Q&A
item in that dialogue was concerning whether item X in a list should
expect to be copied when the containing list is multiplied.

You are the only one talking about applying the multiplication
operator to dicts.

> Huh?
> I'm not yelling any more than you are.  Are ???YOU??? yelling?

Perhaps you're not aware that on the Internet, TYPING IN ALL CAPS is
commonly construed as SHOUTING.


More information about the Python-list mailing list