Verbose and flexible args and kwargs syntax

Eelco hoogendoorn.eelco at gmail.com
Tue Dec 13 03:44:20 EST 2011


On Dec 13, 2:41 am, Ian Kelly <ian.g.ke... at gmail.com> wrote:
> On Mon, Dec 12, 2011 at 4:40 PM, Eelco <hoogendoorn.ee... at gmail.com> wrote:
> >> For a linked list, no *target and no copying is needed:
>
> >> head, tail = llist
>
> > I have no idea what this means.
>
> Each node of a linked list consists of a data member and a "next"
> member, that holds the next node in the list.  The natural container
> for this and the way it is usually implemented in Python is a
> 2-element tuple.  For example:
>
> llist = ('one', ('two', ('three', ('four', None))))
>
> would be a linked list as typically constructed in Python, and it can
> be used in pretty much the same way that lists are used in Lisp.  The
> result of the operation:
>
> head, tail = llist
>
> is:
>
> head = 'one'
> tail = ('two', ('three', ('four', None)))
>
> and as Terry pointed out, no copying is required to do this.  I
> believe deque is also implemented as a doubly-linked list, which is
> probably why you keep referring to it as such, but that is an
> implementation detail.  When you say "linked list" in relation to
> Python, the preceding is what comes to mind.

'for i in llist' is not quite going to fly is it? Thats probably the
reason noone ever uses that construct; its not a proper sequence type.


> >> >>>> head, deque(tail) = somedeque
>
> >> > Is better in every way I can think of (readability, consistence,
> >> > performance) than:
> >> >>>> head, *tail = somedeque
> >> >>>> tail = deque(tail)
>
> >> But your suggestion is much worse in each way than
>
> >> head = somedeque.popleft()
>
> > No its not. First of all, its not semantically equivalent; popleft
> > mutates a collection type, and collection unpacking does not; it
> > creates a set of disjoint views of the collection's data. Whether its
> > worse in terms of readability is debatable, but in terms of the other
> > two stated metrics, your claim of it being any kind of worse is
> > objectively false.
>
> I definitely disagree on readability.  Skimming this thread as I have
> been, it took me a while to get that your proposed syntax would create
> a second deque sharing internal state with the original, rather than
> creating a simple copy of the deque, which is what it looks like it
> should do.

Thats a matter of reading up on the semantics of collection unpacking.
To be honest I dont even know what they are for lists, since I dont
use python 3. But whatever is the case, the important thing is that
the semantics should be uniform regardless of the type to be unpacked.

> Incidentally, while that change is not really central to your syntax
> proposal, I think it would be very messy.  For example, how do you
> propose keeping the length elements in sync?  Inserting an item in one
> may or may not affect the length of the other.  If I append an item to
> the end of one deque, should the other automatically be extended as
> well?  What if the tail node of the second deque occurs after the tail
> node of the deque being appended?  Does the appended element then get
> inserted into the middle of the second deque (I think it would have to
> be)?  If I insert an element into the longer (second) deque that just
> happens to be immediately after the tail of the shorter deque, does
> *that* cause the shorter deque to be automatically extended?  And
> likewise for operations at the head of the deque.
>
> None of these questions have obvious answers as to the "right" way to
> it, and for that reason I think this is probably best left to the user
> to implement a custom deque view class with whatever semantics they
> prefer.

Good point. Copy-on-write semantics could be used, but really one
should have several linked list types reflecting the underlying
implementations. I would like to have an immutable singly linked list
builtin of the standard functional type, which you can only unpack
from one end and renders these issues moot, plus a builtin doubly
linked list with copy-on-write or copy-on-unpacking semantics.

> > Furthermore, this brings us back again to the point I raised several
> > times before. Yes, obviously you can already DO these things, but NOT
> > within the same uniform collection unpacking syntactic construct.
> > Again, you have failed to point out what is wrong with supplying a
> > type constrain to python and let it do the right thing based on that;
> > to reiterate:
>
> > head, tail::deque = deque
>
> Python users generally follow the rule "explicit is better than
> implicit".  Setting a general constraint and letting the language "do
> the right thing" is a kind of black magic that feels off because it
> tends to break that rule.  But that's not to say that black magic
> never wins -- just look at super() and the MRO.

We are not talking black magic here; we are talking about an EXPLICIT
type constraint provided on the very same line.

> > If you dont like the extra characters you have to type; there is of
> > course such a thing as defaults. You can choose:
> > head, tail:: = deque; if the type constraint is omitted, we could make
> > tail a list by default, or my preferred solution, infer it from the
> > right hand side type.
>
> I prefer the former.  If it always creates a list by default, then the
> programmer reading this code three years later knows exactly what the
> type of tail is.  If it instead infers it from the sequence being
> unpacked, then the programmer is forced to infer it as well, and it
> won't necessarily be obvious or even consistent.

Well perhaps, but not always knowing the type of your objects at write-
time is inherent to weakly typed languages; this happens all the time.
Not knowing the type of the sequence to be unpacked is in a sense an
asset; I can use this construct in a function, and unpack any sequence
type in a manner appropriate for it. About the result of the unpacking
I will know just as much as about the input to it; that they are the
same type.



More information about the Python-list mailing list