Verbose and flexible args and kwargs syntax

Ian Kelly ian.g.kelly at gmail.com
Mon Dec 12 20:41:34 EST 2011


On Mon, Dec 12, 2011 at 4:40 PM, Eelco <hoogendoorn.eelco 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.

>> >>>> 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.

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.

> 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.

> 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.

Cheers,
Ian



More information about the Python-list mailing list