I definitely like Terry's idea of using ", ..." to say "and ignore the rest". Simple, elegant and can be restricted to the last element so it works with infinite iterators and large sequences. It also allows incremental unpacking of ordinary iterators.
I still like the idea of an unpacking protocol as well, but the above would cover a lot of use cases without needing a new protocol, and thus should be considered first (since a new protocol is a higher impact change than Terry's syntax suggestion).
Cheers,
Nick.
But is that really so much better thancommand = next(iterargs)# etc.?And to me the ... Looks too much like something that consumes the rest, rather than leaving it.--Guido (not on a real keyboard)
Status quo, 2 items (etc):
from itertools import islice
iterargs = iter(args)
command, subcommand = islice(iterargs, 2) # Grab the first two,
leave the rest
commands[command][subcommand](*iterargs) # Pass the rest to the subcommand
If you want "smart" unpackable objects, why not allow d in your *d example to be something other than a list?
In the case of simple unpacking ("a, b, c = foo"), min_count and max_count will be the same value (3). In the case of extended unpacking ("a, b, c, *d = foo"), min_count would be the smallest length that will not cause an unpacking exception (3, in this case), and max_count would be None.
- It would allow for "smart" unpackable objects (such as __ in my enum example), which would "just work" no matter how many values they're required to produce.
On 2/24/2013 1:24 AM, Guido van Rossum wrote:
But is that really so much better than
command = next(iterargs)
# etc.
?
And to me the ... Looks too much like something that consumes the rest,
rather than leaving it.
I considered $ for $top, but I was sure you would not want to waste $ in this.
But maybe it could be extended to include the following variant:
a, b, *() = iterable
If you want "smart" unpackable objects, why not allow d in your *d example to be something other than a list?
Like, if you have a,*b = range(1,5); b could literally be range(2,5).
On 2/24/2013 5:07 PM, Alex Stewart wrote:
> 1. It is a fairly small change to the language
To me, taking something simple and elegant and complexifying it, to
little benefit I can see other than to solve a problem in the wrong
place, in no small matter.
Certainly, adding a new special method to
some category of objects has not effect unless changes are made to the
interpreter elsewhere to make automatic use of that method. Otherwise,
you could just define a normal method to be used by user code.
> 2. There are (in my opinion) already pretty good parallels with this
> sort of change that have already been implemented in Python (for
> example, separating the concept of "iterable" from the concept of
> "indexable").
The related but distinct concepts of sequential access and random access
are basic to computation and were *always* distinct in Python.
The addition of __iter__ along with __next__
added more benefits than __next__ alone would have.
> 3. It is consistent with the general idea in Python that an object can
> choose to emulate whichever behaviors of other objects make sense,
> and not emulate other ones that do not make sense. In my opinion,
> "iterating", and "unpacking" are two related-but-not-the-same
> language concepts, which currently are unnecessarily entangled.
I do not see that at all. As near as I can tell, both mean 'sequential
access'.
I admit I do not understand your __unpack__ proposal, since it seemed
vague and incomplete to me. But until I see your conceptual distinction,
the details do not matter to me.
> 4. It would help significantly with several types of problems that do
> not currently have great solutions.
I obviously do not see the same pile of problems that would justify a
new special method.
> no way to query an iterator to find out if it has more data available
See how in my separate post:
"Add lookahead iterator (peeker) to itertools"
> João Bernardo wrote:
>> Python already supports this odd syntax
>> a, b, *[] = iterable
Indeed, I didn't know that. :-|
>> because it interprets the [] not as an empty list, but as an empty
>> "list of identifiers". Maybe it could be used for something useful.
>
> No, because it already has a meaning: there must be no more
> values left in the sequence.
>
>> BTW, the del syntax has the same "problem"
>> del a, b, (c,), [d], []
>
> Or just
>
> [] = iterable
>
> The surprising thing is that a special case seems to be
> made for ():
>
>>>> () = []
> File "<stdin>", line 1
> SyntaxError: can't assign to ()
>
> It's surprising because () and [] are otherwise completely
> interchangeable for unpacking purposes.
Not entirely...
>>> a, b, [c, d] = 1, 2, (3, 4)
>>> a, b, (c, d) = 1, 2, (3, 4)
OK.
>>> a, b, *[c, d] = 1, 2, 3, 4
>>> a, b, *(c, d) = 1, 2, 3, 4
OK as well -- *but*:
>>> a, b, [] = 1, 2, [] # it's ok
>>> a, b, () = 1, 2, () # but it's not
File "<stdin>", line 1
SyntaxError: can't assign to ()
...and:
>>> a, b, *[] = 1, 2 # it's ok
>>> a, b, *() = 1, 2 # but it's not
File "<stdin>", line 1
SyntaxError: can't assign to ()
Strange... (inb4: http://www.youtube.com/watch?v=5IgB8XKR23c#t=118s ).
*j
João Bernardo wrote:No, because it already has a meaning: there must be no more
Python already supports this odd syntax
a, b, *[] = iterable
because it interprets the [] not as an empty list, but as an empty "list of identifiers". Maybe it could be used for something useful.
values left in the sequence.
BTW, the del syntax has the same "problem"
del a, b, (c,), [d], []
Or just
[] = iterable
The surprising thing is that a special case seems to be
made for ():
>>> () = []
File "<stdin>", line 1
SyntaxError: can't assign to ()
It's surprising because () and [] are otherwise completely
interchangeable for unpacking purposes
On 2/25/2013 5:25 PM, Alex Stewart wrote:
Negative putdowns are off-topic and not persuasive.
I starting with 1.3 in March 1997 and first posted a month later.
> Then how, prior to the development of the iterator protocol,As I said, by using the original fake-getitem iterator protocol, which still works, instead of the newer iter-next iterator protocol.did one define an object which was accessible sequentially but not
randomly in the Python language?
Back to unpack and informing the source as to the number n of items expected to be requested.
Case 1. The desired response of the source to n is generic.
Case 2. The desired response is specific to a class or even each instance.
Solution: write a method, call it .unpack(n), that returns an iterator that will produce the objects specified in the table. This can be done today with no change to Python. It can be done whether or not there is a .__iter__ method to produce a generic default iterator for the object. And, of course, xxx.unpack can have whatever signature is appropriate to xxx. It seems to me that this procedure can handle any special collection or structure breakup need.
Comment 2: we are not disagreeing that people might want to do custom count-dependent disassembly or that they should be able to do so. It can already be done.
Areas of disagreement:
1. consumer-source interdependency: you seem to think there is something special about the consumer assigning items to multiple targets in one statement, as opposed to doing anything else, including doing the multiple assignments in multiple statements.
2. general usefulness: you want .unpack to be standardized and made a special method. I think it is inherently variable enough and and the need rare enough to not justify that.