Разница между' и '(логическим) и ' & ' (побитовым) в python. Почему разница в поведении со списками против массивов numpy?
что объясняет разницу в поведении булевых и побитовых операций над списками против numpy.массивы?
я путаюсь о соответствующем использовании '&
'vs'and
' в python, проиллюстрированный в следующих простых примерах.
mylist1 = [True, True, True, False, True]
mylist2 = [False, True, False, True, False]
>>> len(mylist1) == len(mylist2)
True
# ---- Example 1 ----
>>>mylist1 and mylist2
[False, True, False, True, False]
#I am confused: I would have expected [False, True, False, False, False]
# ---- Example 2 ----
>>>mylist1 & mylist2
*** TypeError: unsupported operand type(s) for &: 'list' and 'list'
#I am confused: Why not just like example 1?
# ---- Example 3 ----
>>>import numpy as np
>>> np.array(mylist1) and np.array(mylist2)
*** ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
#I am confused: Why not just like Example 4?
# ---- Example 4 ----
>>> np.array(mylist1) & np.array(mylist2)
array([False, True, False, False, False], dtype=bool)
#This is the output I was expecting!
этот ответ, и этот ответ помог мне понять, что 'и' является логической операцией, но '&' это побитовая операция.
Я чтение информация, чтобы лучше понять концепцию побитовые операции, но я изо всех сил пытаюсь использовать эту информацию, чтобы понять Мои выше 4 примера.
обратите внимание, в моей конкретной ситуации, мой желаемый результат-это newlist, где:
len(newlist) == len(mylist1)
newlist[i] == (mylist1[i] and mylist2[i]) #for every element of newlist
Пример 4, выше, привел меня к желаемому результату, так что все в порядке.
но я остался в замешательстве о том, когда/как / почему я должен использовать 'и' vs '&'. Почему списки и numpy массивы ведут себя по-разному с этими операторами?
может ли кто-нибудь помочь мне понять разницу между булевыми и побитовыми операциями, чтобы объяснить, почему они обрабатывают списки и numpy.массивы по-другому?
Я просто хочу убедиться, что я продолжаю правильно использовать эти операции в будущем. Большое спасибо за помощь!
Numpy version 1.7.1
python 2.7
References all inline with text.
редактирование
1) Спасибо @delnan за указание на то, что в моих оригинальных примерах у меня был am двусмысленность, которая скрывала мое глубокое замешательство. Я обновил свои примеры, чтобы прояснить мой вопрос.
7 ответов:
and
проверяет, являются ли оба выражения являются логическиTrue
пока&
(при использованииTrue
/False
значения) тесты, Если обаTrue
.в Python пустые встроенные объекты обычно рассматриваются как логически
False
в то время как непустые встроенные логическиTrue
. Это облегчает общий случай использования, где вы хотите что-то сделать если список пуст, и что-то еще, если список не. Обратите внимание, что это означает, что список [False] логическиTrue
:>>> if [False]: ... print 'True' ... True
Итак, в Примере 1 первый список непустой и поэтому логически
True
, Так что значение истиныand
это то же самое, что и во втором списке. (В нашем случае, второй список не является пустым, и, следовательно, логическиTrue
, но определение этого потребует ненужного шага расчета.)например 2, списки не могут быть объединены в побитового моды, потому что они могут содержать произвольные элементы. Вещи, которые можно комбинировать побитовые включают в себя: истины и ложь, целые числа.
объекты NumPy, напротив, поддерживают векторизованные вычисления. То есть они позволяют выполнять одни и те же операции с несколькими частями данных.
Пример 3 терпит неудачу, потому что массивы NumPy (длины > 1) не имеют значения истинности, поскольку это предотвращает путаницу векторной логики.
Пример 4 - это просто векторизованный бит
and
операции.дно Линия
если вы не имеете дело с массивами и не выполняете математические манипуляции с целыми числами, вы, вероятно, хотите
and
.если у вас есть векторы истинностных значений, которые вы хотите объединить, используйте
numpy
С&
.
булевы операторы короткого замыкания (
and
,or
) не может быть переопределен, потому что нет удовлетворительного способа сделать это без введения новых функций языка или жертвуя коротким замыканием. Как вы можете или не можете знать, они оценивают первый операнд для его истинностного значения и в зависимости от этого значения либо оценивают и возвращают второй аргумент, либо не оценивают второй аргумент и возвращают первый:something_true and x -> x something_false and x -> something_false something_true or x -> something_true something_false or x -> x
обратите внимание, что (результат оценки) фактический операнд, а не его истинностное значение.
единственный способ настроить их поведение переопределить
__nonzero__
(переименован в__bool__
в Python 3), поэтому вы можете повлиять на то, какой операнд возвращается, но не возвращать что-то другое. Списки (и другие коллекции) определяются как "истинные", когда они содержат что-либо вообще, и "ложные", когда они пусты.массивы NumPy отвергают это понятие: для случаев использования, на которые они нацелены, два разных понятия истины общие: (1) является ли какой-либо элемент истинным, и (2) являются ли все элементы истинными. Поскольку эти два полностью (и молча) несовместимы, и ни один из них не является явно более правильным или более распространенным, NumPy отказывается угадывать и требует, чтобы вы явно использовали
.any()
или.all()
.
&
и|
(иnot
, кстати) можете быть полностью исключен, так как они не короткое замыкание. Они могут вернуть все, что угодно, когда переопределены, и NumPy хорошо использует это, чтобы сделать поэлементные операции, как и практически любая другая скалярная операция. Списки, с другой стороны, не транслируют операции по своим элементам. Так же, какmylist1 - mylist2
ничего не значит, аmylist1 + mylist2
значит что-то совсем другое, нет&
оператора для списков.
о
list
во-первых очень важный момент, из которого все будет следовать (я надеюсь).
в обычном Python,
list
не является особенным в любом случае (за исключением наличия симпатичного синтаксиса для построения, что в основном является исторической случайностью). Один раз список[3,2,6]
сделано это, для всех намерений и целей, просто обычный объект в Python, как количество3
, set{3,7}
, или функцияlambda x: x+5
.(Да, он поддерживает изменение его элементов, и он поддерживает итерацию и многое другое, но это именно то, что тип: он поддерживает некоторые операции, не поддерживая некоторые другие. int поддерживает повышение до власти, но это не делает его очень особенным - это просто то, что есть int. лямбда поддерживает вызов, но это не делает его очень особенным - это то, для чего лямбда, в конце концов:).
о
and
and
не является оператором (вы можете назвать его "оператор", но вы можете вызвать" для " оператора слишком.): Операторы в Python (реализуются через) методы, вызываемые для объектов некоторого типа, обычно записываемых как часть этого типа. Метод не может провести оценку некоторых своих операндов, ноand
может (и должен) это сделать.следствием этого является то, что
and
не может быть перегружен, так какfor
не может быть перегружен. Он является полностью общим и взаимодействует через определенный протокол. Что ты можете do-это настройка вашей части протокола, но это не значит, что вы можете изменить поведениеand
полностью. Протокол таков:представьте себе, что Python интерпретирует "a и b" (это не происходит буквально так, но это помогает понять). Когда дело доходит до "и", он смотрит на объект, который он только что оценил (а), и спрашивает его: вы правы? (не: ты
True
?) Если вы являетесь автором класса, вы можете настроить этот ответ. Еслиa
ответ "нет",and
(пропускает b полностью он вообще не оценивается, а) говорит:a
мой результат (не: False-это мой результат).если
a
не отвечаетand
спрашивает его: какова ваша длина? (Опять же, вы можете настроить это как автор С). Еслиa
ответы 0,and
делает то же, что и выше - считает его ложным (не False), пропускает b и даетa
как результат.если
a
отвечает что-то другое, чем 0 на второй вопрос ("какова ваша длина"), или он вообще не отвечает, или он отвечает "Да" на первый ("ты правда"),and
оценивает b и говорит:b
- это мой результат. Обратите внимание, что это делает не задатьb
любые вопросы.другой способ сказать все это, что
a and b
это почти то же самое, чтоb if a else a
, кроме a оценивается только один раз.теперь посидите несколько минут с ручкой и бумагой и убедитесь, что когда {a, b} является подмножеством {True, False}, он работает именно так, как вы ожидаете от булевых операторов. Но я надеюсь, что убедил вас, что это гораздо более общий и, как вы увидите, гораздо более полезный путь.
соединяя эти два вместе
теперь я надеюсь, что вы понимаете ваш пример 1.
and
не имеет значения, является ли mylist1 числом, списком, лямбдой или объектом класса Argmhbl. Он просто заботится об ответе mylist1 на вопросы протокола. И конечно, mylist1 отвечает 5 на вопрос о длине, так и возвращает mylist2. И это все. Это не имеет ничего общего с элементами mylist1 и mylist2 - они нигде не входят в картину.второй пример:
&
onlist
с другой стороны,
&
- это оператор, как и любой другой, как+
например. Он может быть определен для типа путем определения специального метода для этого класса.int
определяет его как побитовое "и", А bool определяет его как логическое" и", но это только один вариант: например, наборы и некоторые другие объекты, такие как представления ключей dict, определяют его как пересечение набора.list
просто не определяет его, вероятно, потому, что Гвидо не думал о каком-либо очевидном способе его определения.включает в себя
на другой ноге: - D, numpy массивы are специальные, или по крайней мере они пытаются быть. Конечно, тупица.массив-это просто класс, он не может переопределить
and
в любом случае, поэтому он делает следующее лучшее: когда его спрашивают "Ты правда", numpy.матрица поднимает ValueError, эффективно говоря: "пожалуйста, перефразируйте вопрос, мой взгляд на истину не вписывается в вашу модель". (Обратите внимание, что сообщение ValueError не говорит оand
- потому что numpy.массив не знает кто задает ему вопрос; он просто говорит о правде.)на
&
, это совершенно другая история. и NumPy.массив может определить его по своему желанию, и он определяет&
последовательно с другими операторами: точечно. Так что Вы, наконец, получите то, что вы хотите.HTH,
Пример 1:
это как и работает оператор.
x и y => если x ложно, то x, еще y
другими словами, так как
mylist1
неFalse
, результат выраженияmylist2
. (Только пустые списки оценка дляFalse
.)пример 2:
The
&
оператор предназначен для побитового и, как вы упомянули. Побитовые операции работают только с числами. Результат a & b - это число, состоящее из 1s в битах, которые равны 1 в обоих a и b. Например:>>> 3 & 1 1
это легче увидеть, что происходит с помощью двоичный литерал (те же цифры, что и выше):
>>> 0b0011 & 0b0001 0b0001
побитовые операции аналогичны в понятие логические операции (правда), но они работают только на битах.
Итак, учитывая пару заявлений о моей машине
- моя машина красная
- у моей машины есть колеса
логическим "и" этих двух утверждений является:
(моя машина красная?) и (есть ли у автомобиля колеса?) = > логическая истина ложного значения
оба из которых верны, по крайней мере для моей машины. Таким образом, значение утверждения как целое-это логически правда.
побитовое "и" этих двух утверждений немного более туманно:
(числовое значение выписку 'мой автомобиль красный') & (числовое значение выписку 'мой автомобиль имеет колеса') => ряд
если python знает, как преобразовать операторы в числовые значения, то он сделает это и вычислит побитовое-и из двух значений. Это может привести вас к мысли, что
&
is взаимозаменяемы сand
, но, как и в приведенном выше примере это разные вещи. Кроме того, для объектов, которые не могут быть преобразованы, вы просто получитеTypeError
.Пример 3 и 4:
Numpy реализует арифметические операции для массивов:
арифметические операции и операции сравнения на ndarrays определяется как элемент-мудрый операции, и, как правило, доходность объектов ndarray как результаты.
но не реализуют логические операции для массивов, потому что вы не удается перегрузить логические операторы в python. Вот почему пример три не работает, но пример четыре делает.
Итак, чтобы ответить на ваш
and
vs&
вопрос: Использоватьand
.побитовые операции используются для изучения структуры числа (какие биты установлены, какие биты не установлены). Этот вид информации главным образом использован внутри низкоуровневые интерфейсы операционной системы ( бит разрешения unix, например). Большинству программ python это знать не нужно.
логические операции (
and
,or
,not
), однако, используются все время.
в Python выражение
X and Y
возвращаетY
, учитывая, чтоbool(X) == True
или какой-либо изX
илиY
оценить значение False, например:True and 20 >>> 20 False and 20 >>> False 20 and [] >>> []
побитовый оператор просто не определен для списков. Но он определен для целых чисел-работает над двоичным представлением чисел. Рассмотрим 16 (01000) и 31 (11111):
16 & 31 >>> 16
NumPy не экстрасенс, он не знает, имеете ли вы в виду что например,
[False, False]
должно быть равноTrue
в логическом выражении. В этом он переопределяет стандартное поведение Python, которое является: "любая пустая коллекция сlen(collection) == 0
иFalse
".вероятно, ожидаемое поведение оператора & массивов NumPy.
операции со списком Python работают на список.
list1 and list2
будет проверить, еслиlist1
пусто, и возвратаlist1
если это так, иlist2
если это не так.list1 + list2
добавляетlist2
доlist1
, Так что вы получите новый список сlen(list1) + len(list2)
элементы.операторы, которые имеют смысл только при применении по элементам, например
&
, раститьTypeError
, поскольку операции по элементам не поддерживаются без циклического перебора элементов.массивы Numpy поддержка элемент-мудрый операции.
array1 & array2
будет вычислить побитовое или для каждого соответствующего элементаarray1
иarray2
.array1 + array2
вычислит сумму для каждого соответствующего элемента вarray1
иarray2
.это не работает для
and
иor
.
array1 and array2
по существу короткая рука для следующего кода:if bool(array1): return array2 else: return array1
для этого вам нужно хорошее определение
bool(array1)
. Для глобальных операций, таких как использовать списки питона, определение заключается в том, чтоbool(list) == True
еслиlist
не пусто, аFalse
если он пустой. Для поэлементных операций numpy существует некоторая неопределенность, следует ли проверять, если какой-либо элемент оценивается вTrue
, или все элементы оценки вTrue
. Потому что оба, возможно, правильно, numpy не догадывается и поднимаетValueError
, когдаbool()
(косвенно) вызывается на массив.
для первого примера и базы на Джанго док
Он всегда будет возвращать второй список, действительно непустой список рассматривается как истинное значение для Python, поэтому python возвращает "последнее" истинное значение, поэтому второй списокIn [74]: mylist1 = [False] In [75]: mylist2 = [False, True, False, True, False] In [76]: mylist1 and mylist2 Out[76]: [False, True, False, True, False] In [77]: mylist2 and mylist1 Out[77]: [False]