[Python-ideas] Two small functional-style-related improvements

Steven D'Aprano steve at pearwood.info
Sun Mar 27 05:41:44 CEST 2011


Jan Kaliszewski wrote:
> Hello.
> 
> IMHO it'd be nice...
> 
> 1. ...to add:
> 
> * operator.is_none -- equivalent to (lambda x: x is None))
> * operator.is_not_none -- equivalent tolambda x: x is not None))
> 
> ...making using 'is None'/'is not None' tests with any(), all(),
> filter(), itertools.takewhile/dropwhile() more convenient and readable
> (possibly also optimised for speed).

How is

import operator
any(map(operator.is_none, iterable))

more convenient and readable than:

any(x is None for x in iterable)

? I'm asking this as someone who likes map and other functional tools.
Now that we have generator expressions and list comprehensions in the 
language, wrapping trivial expressions in a function is far less common.

Likewise, how could a function call that includes 'x is None' be faster 
than 'x is None' alone? The overhead of calling the function would have 
to be negative! We can see this with the existing operator.is_ function:


[steve at sylar ~]$ python3 -m timeit -r 15 -s "from operator import is_" 
"is_(42, None)"
1000000 loops, best of 15: 0.224 usec per loop
[steve at sylar ~]$ python3 -m timeit -r 15 "42 is None"
1000000 loops, best of 15: 0.117 usec per loop

For comparison purposes:

[steve at sylar ~]$ python3 -m timeit -r 15 -s "def f(x): x is None" "f(42)"
1000000 loops, best of 15: 0.378 usec per loop

and just for completeness:

[steve at sylar ~]$ python3 -m timeit -r 15 -s "from operator import is_; 
from functools import partial; f = partial(is_, None)" "f(42)"
1000000 loops, best of 15: 0.301 usec per loop


The possible time saving compared to a pure-Python function is very 
small, and there's rarely a need to use a function when you can just use 
an expression.



> 2. ...to add:
> 
> * operator.anti_caller (or e.g. functools.negator?) -- equivalent to:
> 
> def anti_caller(func):
>     def call_and_negate(*args, **kwargs):
>         return not func(*args, **kwargs)
>     return call_and_negate

This seems to be a decorator, so I don't believe it belongs in the 
operator module. Either way, I don't see the point to it. Why would you 
use this

@functools.negator
def spam(x):
     return something


instead of just this?

def spam(x):
     return not something


What is your use-case for this function?



-- 
Steven




More information about the Python-ideas mailing list