How do I get the opposite (negation) of a Boolean in Python?

后端 未结 7 1509
太阳男子
太阳男子 2020-12-08 03:57

For the following sample:

def fuctionName(int, bool):
    if int in range(...):
        if bool == True:
            return False
        else:
            r         


        
7条回答
  •  北荒
    北荒 (楼主)
    2020-12-08 03:59

    The not operator (logical negation)

    Probably the best way is using the operator not:

    >>> value = True
    >>> not value
    False
    
    >>> value = False
    >>> not value
    True
    

    So instead of your code:

    if bool == True:
        return False
    else:
        return True
    

    You could use:

    return not bool
    

    The logical negation as function

    There are also two functions in the operator module operator.not_ and it's alias operator.__not__ in case you need it as function instead of as operator:

    >>> import operator
    >>> operator.not_(False)
    True
    >>> operator.not_(True)
    False
    

    These can be useful if you want to use a function that requires a predicate-function or a callback.

    For example map or filter:

    >>> lst = [True, False, True, False]
    >>> list(map(operator.not_, lst))
    [False, True, False, True]
    
    >>> lst = [True, False, True, False]
    >>> list(filter(operator.not_, lst))
    [False, False]
    

    Of course the same could also be achieved with an equivalent lambda function:

    >>> my_not_function = lambda item: not item
    
    >>> list(map(my_not_function, lst))
    [False, True, False, True]
    

    Do not use the bitwise invert operator ~ on booleans

    One might be tempted to use the bitwise invert operator ~ or the equivalent operator function operator.inv (or one of the other 3 aliases there). But because bool is a subclass of int the result could be unexpected because it doesn't return the "inverse boolean", it returns the "inverse integer":

    >>> ~True
    -2
    >>> ~False
    -1
    

    That's because True is equivalent to 1 and False to 0 and bitwise inversion operates on the bitwise representation of the integers 1 and 0.

    So these cannot be used to "negate" a bool.

    Negation with NumPy arrays (and subclasses)

    If you're dealing with NumPy arrays (or subclasses like pandas.Series or pandas.DataFrame) containing booleans you can actually use the bitwise inverse operator (~) to negate all booleans in an array:

    >>> import numpy as np
    >>> arr = np.array([True, False, True, False])
    >>> ~arr
    array([False,  True, False,  True])
    

    Or the equivalent NumPy function:

    >>> np.bitwise_not(arr)
    array([False,  True, False,  True])
    

    You cannot use the not operator or the operator.not function on NumPy arrays because these require that these return a single bool (not an array of booleans), however NumPy also contains a logical not function that works element-wise:

    >>> np.logical_not(arr)
    array([False,  True, False,  True])
    

    That can also be applied to non-boolean arrays:

    >>> arr = np.array([0, 1, 2, 0])
    >>> np.logical_not(arr)
    array([ True, False, False,  True])
    

    Customizing your own classes

    not works by calling bool on the value and negate the result. In the simplest case the truth value will just call __bool__ on the object.

    So by implementing __bool__ (or __nonzero__ in Python 2) you can customize the truth value and thus the result of not:

    class Test(object):
        def __init__(self, value):
            self._value = value
    
        def __bool__(self):
            print('__bool__ called on {!r}'.format(self))
            return bool(self._value)
    
        __nonzero__ = __bool__  # Python 2 compatibility
    
        def __repr__(self):
            return '{self.__class__.__name__}({self._value!r})'.format(self=self)
    

    I added a print statement so you can verify that it really calls the method:

    >>> a = Test(10)
    >>> not a
    __bool__ called on Test(10)
    False
    

    Likewise you could implement the __invert__ method to implement the behavior when ~ is applied:

    class Test(object):
        def __init__(self, value):
            self._value = value
    
        def __invert__(self):
            print('__invert__ called on {!r}'.format(self))
            return not self._value
    
        def __repr__(self):
            return '{self.__class__.__name__}({self._value!r})'.format(self=self)
    

    Again with a print call to see that it is actually called:

    >>> a = Test(True)
    >>> ~a
    __invert__ called on Test(True)
    False
    
    >>> a = Test(False)
    >>> ~a
    __invert__ called on Test(False)
    True
    

    However implementing __invert__ like that could be confusing because it's behavior is different from "normal" Python behavior. If you ever do that clearly document it and make sure that it has a pretty good (and common) use-case.

提交回复
热议问题