Загадка для неспящих любителей Python. Почему где-то в результате число, а где то boolean?
Пост начинается с твита. В реплаях не было подробного пояснения, поэтому я решил сделать свое маленькое исследование
Загадка для неспящих любителей Python. Почему где-то в результате число, а где то boolean? pic.twitter.com/p9ExcAi3U6
— Randomazer (@Randomazer) May 15, 2021
Круг 0. Запустим
for x in 0,1:
for y in 0,1:
for z in 0,1:
print (x,y,z, 'result: ', (x and y) or (x and not z))
0 0 0 result: 0
0 0 1 result: 0
0 1 0 result: 0
0 1 1 result: 0
1 0 0 result: True
1 0 1 result: False
1 1 0 result: 1
1 1 1 result: 1
Круг 1
Наблюдения 1
В некоторых случаях выражение возвращает int, а в некоторых boolean
Предположим 1
Дело не в операторе OR и разделим на две проверки
for x in 0,1:
for y in 0,1:
for z in 0,1:
print (x,y,z, 'result1: ', (x and y))
print (x,y,z, 'result2: ', (x and not z))
0 0 0 result1: 0
0 0 0 result2: 0
0 0 1 result1: 0
0 0 1 result2: 0
0 1 0 result1: 0
0 1 0 result2: 0
0 1 1 result1: 0
0 1 1 result2: 0
1 0 0 result1: 0
1 0 0 result2: True
1 0 1 result1: 0
1 0 1 result2: False
1 1 0 result1: 1
1 1 0 result2: True
1 1 1 result1: 1
1 1 1 result2: False
Круг 2
Наблюдения 2
Boolean переменные вылезают только в result2
, так что на result1
сейчас можно не смотреть
Так как единственной разницей между вычисляемыми result в наличии not
Предположим 2
Дело только в not
и выведем x
, y
и z
с и без not
.
Также посмотрим на not not
выражение
for x in 0,1:
for y in 0,1:
for z in 0,1:
print ('x:\t\t', (x))
print ('not x:\t\t', (not x))
print ('y:\t\t', (y))
print ('not y:\t\t', (not y))
print ('z:\t\t', (z))
print ('not z:\t\t', (not z))
print ('not not z:\t', (not not z))
x: 0
not x: True
y: 0
not y: True
z: 0
not z: True
not not z: False
x: 0
not x: True
y: 0
not y: True
z: 1
not z: False
not not z: True
x: 0
not x: True
y: 1
not y: False
z: 0
not z: True
not not z: False
x: 0
not x: True
y: 1
not y: False
z: 1
not z: False
not not z: True
x: 1
not x: False
y: 0
not y: True
z: 0
not z: True
not not z: False
x: 1
not x: False
y: 0
not y: True
z: 1
not z: False
not not z: True
x: 1
not x: False
y: 1
not y: False
z: 0
not z: True
not not z: False
x: 1
not x: False
y: 1
not y: False
z: 1
not z: False
not not z: True
Круг 3
Наблюдения 3
- Все строки с
not
стали boolean
Предположение 3
Необходимо проверить, как работают and
и or
с not
for x in 0,1:
for y in 0,1:
print (x, 'AND', y, ':\t\t', x and y)
print (x, 'AND NOT', y, ':\t\t', x and not y)
print ('NOT', x, 'AND', y, ':\t\t', not x and y)
print ('NOT', x, 'AND', 'NOT', y, ':\t', not x and not y)
print (x, 'OR', y, ':\t\t', x or y)
print (x, 'OR', 'NOT', y, ':\t\t', x or not y)
print ('NOT', x, 'OR', y, ':\t\t', not x or y)
print ('NOT', x, 'OR', 'NOT', y, ':\t', not x or not y)
0 AND 0 : 0
0 AND NOT 0 : 0
NOT 0 AND 0 : 0
NOT 0 AND NOT 0 : True
0 OR 0 : 0
0 OR NOT 0 : True
NOT 0 OR 0 : True
NOT 0 OR NOT 0 : True
0 AND 1 : 0
0 AND NOT 1 : 0
NOT 0 AND 1 : 1
NOT 0 AND NOT 1 : False
0 OR 1 : 1
0 OR NOT 1 : False
NOT 0 OR 1 : True
NOT 0 OR NOT 1 : True
1 AND 0 : 0
1 AND NOT 0 : True
NOT 1 AND 0 : False
NOT 1 AND NOT 0 : False
1 OR 0 : 1
1 OR NOT 0 : 1
NOT 1 OR 0 : 0
NOT 1 OR NOT 0 : True
1 AND 1 : 1
1 AND NOT 1 : False
NOT 1 AND 1 : False
NOT 1 AND NOT 1 : False
1 OR 1 : 1
1 OR NOT 1 : 1
NOT 1 OR 1 : 1
NOT 1 OR NOT 1 : False
Круг 4
Наблюдения 4
- Если первый аргумент
or
являетсяtrue
или1
, то в целях оптимизации (?) вторая половина не проверяется. Тип первого аргумента сохраняется. - Если первый аргумент
or
являетсяFalse
или0
, то его тип данных ингорируется, наследуется только тип второго аргумента. - Тип первого аргумента
and
игнорируется, наследуется только тип второго агрумента not
всегда приводит вывод к boolean типу
Выводы
Будьте, блядь, предельно осторожны, duck typing - крайне непредсказуемая штука