[Python-Dev] Half-baked proposal: * (and **?) in assignments

Alex Martelli aleax@aleax.it
Mon, 25 Nov 2002 09:17:09 +0100

On Monday 25 November 2002 01:07 am, Brett Cannon wrote:
> > Hmmm, not really: list(L) returns a list L1 such that L1 == L but id(L1)
> > != id(L) -- i.e., list and dict give a *shallow copy* of their list and
> > dict argument respectively.  iter is different...
> Oops.  Rather cool, though, since that is a nice way to copy a list just
> like the [:] trick.

Not quite "just like", which is good, because there is not a total overlap of 
functionality but rather two useful idioms with different semantics:

x = y[:]

binds x to a sequence of the same type as sequence y (tuple, list, string, 
...) -- whatever (if anything) now happens to y, x remains bound to that, and 
y's type is preserved as the type of x;

x = list(y)

binds x to a LIST with the same items as iterable y (tuple, list, string, 
file, dict, ...) -- you can now alter x with any or all list operations, and 
y will not be affected in any way.

> > No, but that's because lists and dicts (and strings) package their
> > functionality up as methods, so there's no need to have any supporting
> > module.  Tuples don't need anything special.  Generic iterators do not
> > offer pre-cooked rich functionality nor do they have methods usable to
> > locate such functionality, yet clearly they could well use it, therefore
> > a module appears to be exactly the right place to locate such
> > functionality in.
> True, but there are possible things that are handy but you don't want to
> have as a full-blown method (and of course because I have said this no
> example is coming to my mind).

Easy examples for lists include random.shuffle and bisect.insert -- even 
though lists offer lots of functionality as methods, Python ALSO offers 
supporting modules with functions for more specialized needs.

> I guess I just have not come up with that many fancy tricks for iterators
> that would fill a module.  The only other thing I have found handy is a
> wrapper function that keeps copies of what an iterator returns so you can
> index the result later; memoization for iterators.

That is one example of a wrapper that could well use support from the 
underlying iterator it is wrapping -- if the underlying iterator already has 
e.g. a list, it WOULD be nice for the memoizer to be able to get to it rather 
than storing stuff yet once again, e.g. by the iterator exposing an optional 
special method for the purpose.

Most "tricks" (not really tricky nor fancy) are on a less fundamental level, 
indeed quite analogous to the functionality of the bisect module.  For 
example, merging 2 or N iterators, each of which returns items in sorted 
(i.e. increasing) order, into one iterator which iterleaves said items and 
also ensures it returns them in sorted (increasing) order.  That's easy to 
code, just as binary-search is easy to code, but frequently useful, and silly 
to have people recode a hundred times with some risk of silly coding bugs.

Other things, mostly even less fancy, are strongly suggested by languages 
which have a long tradition of lazy (non-strict) lists, such as Haskell, for 
example take and drop.  Often I want for example to work on (e.g.) lines 3 to 
7 included of a file, and "for line in take(5, drop(2, open("thefile"))):" is 
the first approach that comes to mind -- but as take and drop are not in the 
standard library I confess I most often don't bother coding them up and end 
up with less-clear and slightly more complicated code as a result.

Nothing Earth-shaking, of course, whence my musing that delaying this until 
some larger slice of the Python community gets used to iterator operations 
and some consensus emerges on them may be preferable.