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