'Python negate boolean function

A python boolean function can easily be negated with lambda functions, but it's a bit verbose and hard to read for something so basic, for example:

def is_even(n):
    return n % 2 == 0

odds_under_50 = filter(lambda x: not is_even(x), range(50))

I'm wondering if there is a function to do this in the standard library, which might look like:

odds_under_50 = filter(negate(is_even), range(50))


Solution 1:[1]

As far as I know there is no builtin function for that, or a popular library that does that.

Nevertheless, you can easily write one yourself:

from functools import wraps

def negate(f):
    @wraps(f)
    def g(*args,**kwargs):
        return not f(*args,**kwargs)
    g.__name__ = f'negate({f.__name__})'
    return g

You can then use:

odds_under_50 = filter(negate(is_even), range(50))

The negate function works for an arbitrary amount of parameters of the given function: if you would have defined is_dividable(x,n=2). Then negate(is_dividable) is a function with two arguments (one optional) that would also accept these parameters.

Solution 2:[2]

In case of filter you can use ifilterfalse from itertools.

Solution 3:[3]

You can create a decorator:

def negate(function):
    def new_function(*args, **kwargs):
       return not function(*args, **kwargs)
    return new_function


def is_even(x):
    return x % 2 == 0

print is_even(1)
print is_even(2)

is_odd = negate(is_even)
print is_odd(1)
print is_odd(2)

This decorator can also be used with @negate.

@negate
def is_odd(x):
    return x % 2 == 0

Solution 4:[4]

With funcy's or toolz's compose function you can negate the function like that:

import operator

import funcy

is_odd = funcy.compose(operator.not_, is_even)

If you want to make it more readable:

def negate(func):
    return funcy.compose(operator.not_, func)

is_odd = negate(is_even)

# or without creating the function directly
print(negate(is_even)(5))

The funcy library has a lot of other useful functions for functional programming.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 lukeg
Solution 3 eyllanesc
Solution 4