[Python-ideas] Allow "assigning" to Ellipse to discard values.

Chris Kaynor ckaynor at zindagigames.com
Tue Feb 10 22:26:11 CET 2015


On Tue, Feb 10, 2015 at 1:01 PM, Spencer Brown <spencerb21 at live.com> wrote:
> Basically, in any location where a variable name is provided for assignment (tuple unpacking, for loops, function parameters, etc) a variable name can be replaced by '...' to indicate that that value will not be used. This would be syntactically equivalent to del-ing the variable immediately after, except that the assignment never needs to be done.

The canonical way to do this is to use the variable "_" (some guides
recommend "__" for various reasons) for those names. Note that it is
perfectly valid to assign to the same name multiple times in a
statement.

>
> Examples:
>>>> tup =  ('val1', 'val2', (123, 456, 789))
>>>> name, ..., (..., value, ...) = tup
> instead of:
>>>> name = tup[0]
>>>> value = tup[2][1]
> This shows slightly more clearly what format the tuple will be in, and provides some additional error-checking - the unpack will fail if the tuple is a different size or format.

Or, as it already works: "name, _, (_, value, _) = tup". There is not
really any benefit to the proposed syntax.

>
>>>> for ... in range(100):
>>>>    pass
> This particular case could be optimised by checking to see if the iterator has a len() method, and if so directly looping that many times in C instead of executing the __next__() method repeatedly.

Same here. "for _ in range(100)". Note, however, this does not use an
optimized form (_ could be referenced in the loop). I'm not sure how
much gain you would have in many cases from the optimization, and
attempting such an optimization could, in fact, slow stuff down in
some cases (extra look-ups and branches). Ultimately, such would
require profiling of the change, and also considerations as to whether
it could result in unexpected behavior.
>
>>>> for i, ... in enumerate(object):
> is equivalent to:
>>>> for i in range(len(object)):
> The Ellipse form is slightly more clear and works for objects without len().

As above: "for i, _ in enumerate(object):" already works. Again, there
is not really any benefit to the proposed syntax.

>
>>>> first, second, *... = iterator
> In the normal case, this would extract the first two values, and exhaust the rest of the iterator. Perhaps this could be special-cased so the iterator is left alone, and the 3rd+ values are still available.

I would be much more tempted to use:
    first = next(iterator)
    second = next(iterator)
for the case where I don't want to exhaust the iterator. I feel it is
much clearer as to the meaning.

>
>>>> def function(param1, ..., param3, key1=True, key2=False, **...):
>>>>     pass
> This could be useful when overriding functions in a subclass, or writing callback functions. Here we don't actually need the 2nd argument. The '**...' would be the only allowable form of Ellipse in keyword arguments, and just allows any other keywords to be given to the function.

Here is the first case that the "_" trick on its own does not work as
you cannot use the same argument multiple times in a function
definition. I would imagine this has to do with named argument
passing. Similar tricks could still be used, however, by merely
appending numbers: "def function(param1, _0, param3, key1=True,
key2=False, **_1)".

In the case of matching signatures, I would be extremely cautious
about renaming any arguments or eliminating keyword arguments due to
the ability to pass any arguments by name.

For example, in the example provided (presuming logic in the naming of
the parameters in the base class and eliminating the ** part), a valid
call could look like: function(param3=a, param1=b, param2=c), which
would result in errors if the parameters got renamed.


More information about the Python-ideas mailing list