The Python Oracle

How exactly does the behavior of Python bool and numpy bool_ differ?

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
and get $2,000 discount on your first invoice
--------------------------------------------------

Take control of your privacy with Proton's trusted, Swiss-based, secure services.
Choose what you need and safeguard your digital life:
Mail: https://go.getproton.me/SH1CU
VPN: https://go.getproton.me/SH1DI
Password Manager: https://go.getproton.me/SH1DJ
Drive: https://go.getproton.me/SH1CT


Music by Eric Matyas
https://www.soundimage.org
Track title: Techno Intrigue Looping

--

Chapters
00:00 How Exactly Does The Behavior Of Python Bool And Numpy Bool_ Differ?
02:49 Answer 1 Score 3
03:46 Accepted Answer Score 11
05:54 Answer 3 Score 1
06:15 Answer 4 Score 1
07:13 Thank you

--

Full question
https://stackoverflow.com/questions/5590...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #numpy

#avk47



ACCEPTED ANSWER

Score 11


In [119]: np.array([1,0,2,0],dtype=bool)                                             
Out[119]: array([ True, False,  True, False])

In [120]: np.array([1, False, 2, False, []])                                         
Out[120]: array([1, False, 2, False, list([])], dtype=object)

Note the dtype. With object dtype, the elements of the array are Python objects, just like they are in the source list.

In the first case the array dtype is boolean. The elements represent boolean values, but they are not, themselves, Python True/False objects. Strictly speaking Out[119] does not contain np.bool_ objects. Out[119][1] is type bool_, but that's the result of the 'unboxing'. It's what ndarray indexing produces when you ask for an element. (This 'unboxing' distinction is true for all non-object dtypes.)

Normally we don't create dtype objects, preferring np.array(True), but to follow your example:

In [124]: np.bool_(True)                                                             
Out[124]: True
In [125]: type(np.bool_(True))                                                       
Out[125]: numpy.bool_
In [126]: np.bool_(True) is True                                                     
Out[126]: False
In [127]: type(True)                                                                 
Out[127]: bool

is is a strict test, not just for equality, but identity. Objects of different classes don't satisfy a is test. Objects can satisfy the == test without satisfying the is test.

Let's play with the object dtype array:

In [129]: np.array([1, False, 2, np.bool_(False), []])                               
Out[129]: array([1, False, 2, False, list([])], dtype=object)
In [130]: [i is False for i in _]                                                    
Out[130]: [False, True, False, False, False]

In the Out[129] display, the two False objects display the same, but the Out[130] test shows they are different.


To focus on your questions.

  • np.bool_(False) is a unique object, but distinct from False. As you note it has many of the same attributes/methods as np.array(False).

  • If the array dtype is bool it does not contain Python bool objects. It doesn't even contain np.bool_ objects. However indexing such an array will produce a bool_. And applying item() to that in turn produces a Python bool.

  • If the array object dtype, it most likely will contain Python bool, unless you've taken special steps to include bool_ objects.




ANSWER 2

Score 3


There is some confusion with the variables, what is happening is a "confusion" between the module and python, use isinstance(variable, type) to check what is it an if is usable on your code.

Creating a single variable as a bool variable works just fine, python reeds it correctly:

np_bool = np.bool(True)
py_bool = True

print(isinstance(np_bool, bool)) # True
print(isinstance(py_bool, bool)) # True

But with lists it can be different, numpy bool lists are not bool values on a list as you can see in this example:

# Regular list of int
arr0 = [-2, -1, 0, 1, 2]

# Python list of bool
arr1 = [True, False, True, False]

# Numpy list of bool, from int / bool
arr3_a = np.array([-2, -1, 0, 1, 2], dtype=bool)
arr3_b = np.array([True, False, True, False], dtype=bool)

print(isinstance(arr0[0], int))    # True
print(isinstance(arr1[0], bool))   # True

print(isinstance(arr3_a[0], bool)) # False
print(isinstance(arr3_b[0], bool)) # False

In order to use a variable from the numpy list is required a conversion with bool()

arr3_a = np.array([-2, -1, 0, 1, 2], dtype=bool)

x = (bool(arr3_a[0]) is True)
print(isinstance(x, bool)) # True

Quick example of use:

arr3_a = np.array([-2, -1, 0, 1, 2], dtype=bool)

for c in range(0, len(arr3_a)):
    if ( bool(arr3_a[c]) == True ):
        print(("List value {} is True").format(c))
    else:
        print(("List value {} is False").format(c))



ANSWER 3

Score 1


Another difference is that automatic casting to integers can be done on np.bool but not on np.bool_.

This is needed, for example, here

>>> np.bool(False) - np.bool(True)
-1

>>> np.bool_(False) - np.bool_(True)
TypeError: numpy boolean subtract, the `-` operator, is not supported, use the bitwise_xor, the `^` operator, or the logical_xor function instead.




ANSWER 4

Score 1


Everything here are behaving identically except the ones commented. (extending M.M.'s answer with more details on the comparison of normal boolean behavior vs numpy_boolean behaviour)

  def _test():
    npT1 = np.bool_(True)
    npT2 = np.bool_(True)
    npF1 = np.bool_(False)
    npF2 = np.bool_(False)
    # test_1
    print(npT1 is True)  #npT1 is not python boolean, this will be false
    print(npT1 is False)
    print(npT1 == True)
    print(npT1 == False)
    print(npF1 is True)
    print(npF1 is False)
    print(npF1 == True)
    print(npF1 == False)

    print("vs")

    print(True is True)
    print(True is False)
    print(True == True)
    print(True == False)
    print(npF1 is True)
    print(npF1 is False)
    print(npF1 == True)
    print(npF1 == False)
    
    print("------2----")
    # test_2
    print(npT1 is npT2)
    print(npT1 is npT1)
    print(npT1 == npT2)
    print(npT1 and npT2)
    print(npT1 or npT2)

    print("vs")

    print(True is True)
    print(True is True)
    print(True == True)
    print(True and True)
    print(True or True)
    print("-----3-----")
    # test_3
    print(npT1 is npF1)
    print(npT1 == npF1)
    print(npT1 and npF1)
    print(npT1 or npF1)

    print("vs")

    print(True is False)
    print(True == False)
    print(True and False)
    print(True or False)
    print("-----4-----")
    # test_4
    print(npF1 is npF2)
    print(npF1 == npF2)
    print(npF1 and npF2)
    print(npF1 or npF2)

    print("vs")

    print(False is False)
    print(False == False)
    print(False and False)
    print(False or False)
    print("-----5-----")
    # test_5
    print(not npT1)
    print(not npF1)

    print("vs")

    print(not True)
    print(not False)
    print("-----6-----")
    # test_6
    #print(npF1 - npT1)  ! TypeError: numpy boolean subtract, the `-` operator, is not supported, use the bitwise_xor, the `^` operator, or the logical_xor function instead.
    print(False - True)