[Python-ideas] Allow callables in slices

Michel Desmoulin desmoulinmichel at gmail.com
Sat Jun 9 09:28:11 EDT 2018



Le 09/06/2018 à 11:47, Steven D'Aprano a écrit :
> On Sat, Jun 09, 2018 at 11:17:05AM +0200, Michel Desmoulin wrote:
>> Such as that:
>>
>>     def starting_when(element):
>>         ...
>>
>>     a_list[starting_when:]
> 
>> Is equivalent to:
> [...]
>>     list(dropwhile(lambda x: not starting_when(x), a_list))
>>
> 
> That looks like a slice from an index to the end of the list. Things 
> which are similar should look similar, but things which are different 
> should NOT look similar.
> 

The semantic is [start_condition:stop_condition:step].

Here condition can be an index or something more complex.

Just like you can do dictionary[key], but key can be a complex object
with a custom __hash__ executing weird computation.

Just like you can sorted() on natural values or pass a callable as a key.

Just like you can re.replace() with a string or a function.

> What would:
> 
>     alist[callable:callable:callable]
> 
> do? How about this one?
> 
>     alist[7:callable:-1]

ValueError("Step cannot be used when callables are part of a slice")

However:

    alist[7:callable]

Would be:

    list(dropwhile(lambda x: not starting_when(x), islice(alist, 7, None)))


Example, open this files, load all lines in memory, skip the first line,
then get all the line until the first comment:

    import itertools

    def is_commented(line):
        return lines.startwith('#')

    def lines():
        with open('/etc/fstab'):
            lines = f.readlines()[1:]
            return list(itertools.dropwhile(lines, is_commented)

Becomes:

    def is_commented(line):
        return lines.startwith('#')

    def lines():
        with open('/etc/fstab'):
            return f.readlines()[1:is_commented]

It's not about how much shorter is is, but it is very nice to read.

Of course I'd prefer to have slicing on generators, since here we load
the entire file in memory. But I already suggested it several times on
python-idea and the dictator killed it. For files like fstab it's ok
since they are small.
> 
> If there are not meaningful interpretations of callables as part of 
> general slice notation, then we shouldn't use slice notation as a 
> shortcut for dropwhile.
> 
> Rather than give this syntactic support, I'd rather add a new function 
> to itertools that composes takewhile and dropwhile:

It's not syntaxic support. You can already pass callables and the
interpreter accept it fine.

But the underlying types raise TypeError because they don't know how to
use that. Just like you can pass tuples, but CPython can't use them,
while numpy can.


> 
> 
> def between(iterable, startcondition, endcondition):
>     it = iter(iterable)
>     return takewhile(lambda x: not endcondition(x), 
>            dropwhile(lambda x: not startcondition(x), it)
>            )
Or accept callables in islice.



More information about the Python-ideas mailing list