Сравнение с логическими массивами numpy VS PEP8 E712

PEP8 E712 требует, чтобы "сравнение с True должно быть if cond is True: или if cond:".

Но если я буду следовать этому PEP8, я получу другие/неправильные результаты. Почему?

In [1]: from pylab import *

In [2]: a = array([True, True, False])

In [3]: where(a == True)
Out[3]: (array([0, 1]),)
# correct results with PEP violation

In [4]: where(a is True)
Out[4]: (array([], dtype=int64),)
# wrong results without PEP violation

In [5]: where(a)
Out[5]: (array([0, 1]),)
# correct results without PEP violation, but not as clear as the first two imho. "Where what?"

person Framester    schedule 01.03.2013    source источник
comment
Где вы находите этот PEP8 E712?   -  person mgilson    schedule 01.03.2013
comment
Это специальный диагностический вывод инструмента pep8: github.com/jcrocholl. /pep8/blob/master/pep8.py#L900. Обратите внимание, что в данном случае это неправильно, потому что a is True не имеет смысла делать с массивом.   -  person nneonneo    schedule 01.03.2013
comment
@mgilson Вы также можете искать python linter. В большинстве/некоторых IDE есть плагины для проверки pep8 вашего кода.   -  person Framester    schedule 01.03.2013
comment
@Framester - Но на самом деле это не происходит из PEP8 - Быстрый поиск слов в PEP 8 для True показывает, что это только в документе 3 раза. Все в разделе Не сравнивайте логические значения с True или False с помощью ==. который просто говорит не делайте if a == True: - вместо этого делайте if a:. Я бы сказал, что в этом случае ваш linter неверен :) (И я бы рекомендовал подать отчет об ошибке)   -  person mgilson    schedule 01.03.2013


Ответы (2)


Этот совет применим только к if заявлениям, проверяющим "правдивость" значения. numpy это другой зверь.

>>> a = np.array([True, False]) 
>>> a == True
array([ True, False], dtype=bool)
>>> a is True
False

Обратите внимание, что a is True всегда равно False, потому что a — это массив, а не логическое значение, а is выполняет простую проверку равенства ссылок (например, только True is True; None is not True).

person nneonneo    schedule 01.03.2013

"True" Numpy - это не то же самое "True", что и "True" Python, и поэтому is терпит неудачу:

>>> import numpy as np
>>> a = np.array([True, True, False])
>>> a[:]
array([ True,  True, False], dtype=bool)
>>> a[0]
True
>>> a[0]==True
True
>>> a[0] is True
False
>>> type(a[0])
<type 'numpy.bool_'>
>>> type(True)
<type 'bool'>

Кроме того, в частности, PEP 8 говорит НЕ использовать 'is ' или '==' для логических значений:

Don't compare boolean values to True or False using ==:

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

Пустой массив numpy проверяет ложность так же, как пустой список Python или пустой dict:

>>> [bool(x) for x in [[],{},np.array([])]]
[False, False, False] 

В отличие от Python, пустой массив из одного ложного элемента проверяет ложность:

>>> [bool(x) for x in [[False],[0],{0:False},np.array([False]), np.array([0])]]
[True, True, True, False, False]

Но вы не можете использовать эту логику с массивом numpy с более чем одним элементом:

>>> bool(np.array([0,0]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Таким образом, «дух» PEP 8 с Numpy, вероятно, заключается только в проверке правдивости каждого элемента:

>>> np.where(np.array([0,0]))
(array([], dtype=int64),)
>>> np.where(np.array([0,1]))
(array([1]),)

Или используйте any:

>>> np.array([0,0]).any()
False
>>> np.array([0,1]).any()
True

И имейте в виду, что это не то, что вы ожидаете:

>>> bool(np.where(np.array([0,0])))
True

Так как np.where возвращает непустой кортеж.

person dawg    schedule 01.03.2013