Python "in" не проверяет тип?

>>> False in [0]
True
>>> type(False) == type(0)
False

Я наткнулся на это:

Для моего модульного тестирования я создал списки допустимых и недопустимых значений для каждого из моих типов. (с "моими типами" я имею в виду, что они не на 100% равны типам python) Поэтому я хочу перебрать список всех значений и ожидать, что они пройдут, если они будут в моих действительных значениях, а с другой стороны, потерпят неудачу, если они не являются. Теперь это не так хорошо:

>>> valid_values = [-1, 0, 1, 2, 3]
>>> invalid_values = [True, False, "foo"]
>>> for value in valid_values + invalid_values:
...     if value in valid_values:
...         print 'valid value:', value
... 
valid value: -1
valid value: 0
valid value: 1
valid value: 2
valid value: 3
valid value: True
valid value: False

Конечно, я не согласен с двумя последними действительными значениями.

Означает ли это, что мне действительно нужно перебирать мои действительные_значения и сравнивать тип?

Ответы

Ответ 1

Как писали другие, код "in" не делает того, что вы хотите. Вам нужно что-то еще.

Если вам действительно нужна проверка типа (где проверка выполняется точно для одного и того же типа), вы можете указать тип в списке:

>>> valid_values = [(int, i) for i in [-1, 0, 1, 2, 3]]
>>> invalid_values = [True, False, "foo"]
>>> for value in [v[1] for v in valid_values] + invalid_values:
...   if (type(value), value) in valid_values:
...     print value, "is valid"
...   else:
...     print value, "is invalid"
... 
-1 is valid
0 is valid
1 is valid
2 is valid
3 is valid
True is invalid
False is invalid
foo is invalid
>>> 

Обработка подтипов немного сложнее и будет зависеть от того, что вы хотите сделать.

Ответ 2

Проблема не в проверке отсутствующего типа, а в Python bool является подклассом int. Попробуйте следующее:

>>> False == 0
True
>>> isinstance(False, int)
True

Ответ 3

Согласно документации, __contains__ выполняется путем итерации элементов коллекции и тестирования с помощью ==. Следовательно, фактическая проблема вызвана тем, что False == 0 есть True.

Ответ 4

Так как True == 1 и False == 0 трудно различать два.

Один возможный, но безобразный подход (который также не гарантированно работает во всех реализациях Python, но должен быть ОК в CPython):

>>> for value in valid_values + invalid_values:
...    if value in valid_values and not any(v is value for v in invalid_values):
...        print ('valid value:', value)
...
valid value: -1
valid value: 0
valid value: 1
valid value: 2
valid value: 3