Co wyjaśnia różnicę w zachowaniu operacji logicznych i bitowych na listach w porównaniu z tablicami NumPy?
Jestem zdezorientowany co do odpowiedniego użycia &
vs and
w Pythonie, co ilustrują poniższe przykłady.
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 would have expected [False, True, False, False, False]
# ---- Example 2 ----
>>> mylist1 & mylist2
TypeError: unsupported operand type(s) for &: 'list' and 'list'
# Why not just like example 1?
>>> import numpy as np
# ---- Example 3 ----
>>> 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()
# 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!
Ta odpowiedź i ta odpowiedź pomogły mi zrozumieć, że and
jest to operacja logiczna, ale &
operacja bitowa.
Czytałem o operacjach bitowych, aby lepiej zrozumieć koncepcję, ale staram się wykorzystać te informacje, aby nadać sens moim powyższym 4 przykładom.
Przykład 4 doprowadziły mnie do żądanego wyjścia, tak że jest w porządku, ale jestem nadal mylić o tym, kiedy / jak / dlaczego należy używać and
vs &
. Dlaczego listy i tablice NumPy zachowują się inaczej z tymi operatorami?
Czy ktoś może mi pomóc zrozumieć różnicę między operacjami logicznymi i bitowymi, aby wyjaśnić, dlaczego inaczej obsługują listy i tablice NumPy?
np.bitwise_and()
inp.logical_and()
i przyjaciele, aby uniknąć nieporozumień.mylist1 and mylist2
niemylist2 and mylist1
zwraca tego samego wyniku, co , ponieważ zwracana jest druga lista wskazana przez delnan.Odpowiedzi:
and
sprawdza, czy oba wyrażenia są logiczne,True
podczas&
gdy (gdy są używane zTrue
/False
values) testuje, jeśli oba sąTrue
.W Pythonie puste obiekty wbudowane są zwykle traktowane jako logiczne,
False
podczas gdy niepuste obiekty wbudowane są logiczneTrue
. Ułatwia to typowy przypadek użycia, w którym chcesz coś zrobić, jeśli lista jest pusta, a coś innego, jeśli lista nie jest. Zauważ, że oznacza to, że lista [False] jest logicznaTrue
:Tak więc w przykładzie 1 pierwsza lista nie jest pusta, a zatem logicznie
True
, więc prawdziwa wartośćand
jest taka sama, jak druga lista. (W naszym przypadku druga lista nie jest pusta i dlatego jest logicznaTrue
, ale zidentyfikowanie tego wymagałoby niepotrzebnego kroku obliczeniowego).Na przykład 2, list nie można łączyć w sensowny sposób w sposób bitowy, ponieważ mogą zawierać dowolne niepodobne do siebie elementy. Rzeczy, które można łączyć bitowo, to: prawda i fałsz, liczby całkowite.
Z kolei obiekty NumPy obsługują obliczenia wektoryzowane. Oznacza to, że umożliwiają wykonywanie tych samych operacji na wielu fragmentach danych.
Przykład 3 zawodzi, ponieważ tablice NumPy (o długości> 1) nie mają wartości prawdziwej, ponieważ zapobiega to pomyłkom w logice wektorowej.
Przykład 4 to po prostu wektoryzowana
and
operacja bitowa .Podsumowanie
Jeśli nie masz do czynienia z tablicami i nie wykonujesz operacji matematycznych na liczbach całkowitych, prawdopodobnie chcesz
and
.Jeśli masz wektory wartości prawdy, które chcesz połączyć, użyj
numpy
z&
.źródło
O
list
Najpierw bardzo ważny punkt, od którego wszystko się potoczy (mam nadzieję).
W zwykłym Pythonie
list
nie jest niczym szczególnym (z wyjątkiem posiadania ładnej składni do konstruowania, co jest głównie historycznym przypadkiem). Utworzona lista[3,2,6]
jest pod każdym względem zwykłym obiektem Pythona, takim jak liczba3
, zestaw{3,7}
lub funkcjalambda x: x+5
.(Tak, obsługuje zmianę swoich elementów, obsługuje iterację i wiele innych rzeczy, ale tym właśnie jest typ: obsługuje niektóre operacje, podczas gdy inne nie obsługuje. Int obsługuje podnoszenie do potęgi, ale to nie jest uczyń go wyjątkowym - po prostu tym jest int. lambda obsługuje wywoływanie, ale to nie czyni go wyjątkowym - w końcu do tego służy lambda :).
O
and
and
nie jest operatorem (możesz go nazwać „operatorem”, ale możesz też zadzwonić do operatora „for” :). Operatory w Pythonie to (zaimplementowane) metody wywoływane na obiektach pewnego typu, zwykle napisane jako część tego typu. Nie ma sposobu, aby metoda zawierała ocenę niektórych swoich operandów, aleand
może (i musi) to zrobić.Konsekwencją tego jest to, że
and
nie można go przeciążać, tak jakfor
nie można przeciążać. Jest to całkowicie ogólne i komunikuje się za pomocą określonego protokołu. Co można zrobić, to dostosować część protokołu, ale to nie znaczy, można zmienić zachowanieand
całkowicie. Protokół jest następujący:Wyobraź sobie, że Python interpretuje „a i b” (nie dzieje się to dosłownie w ten sposób, ale pomaga to zrozumieć). Jeśli chodzi o „i”, patrzy na obiekt, który właśnie ocenił (a) i pyta: czy to prawda? ( NIE : jesteś
True
?) Jeśli jesteś autorem klasy a, możesz dostosować tę odpowiedź. Jeślia
odpowie „nie”and
(całkowicie pomija b, nie jest ono w ogóle oceniane i) mówi:a
jest moim wynikiem ( NIE : Fałsz to mój wynik).Jeśli
a
nie odpowiada,and
pyta: jaka jest twoja długość? (Ponownie, możesz dostosować to jako autora
klasy). Jeślia
odpowiada 0,and
robi to samo, co powyżej - uważa to za fałszywe ( NIE fałszywe), pomija b i podajea
wynik.Jeśli
a
odpowie coś innego niż 0 na drugie pytanie („jaka jest twoja długość”), lub w ogóle nie odpowie lub odpowie „tak” na pierwsze pytanie („czy jesteś prawdziwy”),and
ocenia b i mówi:b
to mój wynik. Zauważ, że NIE zadajeb
żadnych pytań.Innym sposobem na powiedzenie tego wszystkiego jest to, że
a and b
jest prawie tak samo, jakb if a else a
, z wyjątkiem tego, że a jest oceniane tylko raz.Teraz usiądź na kilka minut z długopisem i kartką i przekonaj się, że kiedy {a, b} jest podzbiorem {Prawda, Fałsz}, to działa dokładnie tak, jak można by oczekiwać od operatorów boolowskich. Mam jednak nadzieję, że przekonałem Cię, że jest on znacznie bardziej ogólny i, jak zobaczysz, w ten sposób znacznie bardziej przydatny.
Łącząc te dwa razem
Mam nadzieję, że rozumiesz swój przykład 1.
and
Nie obchodzi mnie, czy mylist1 jest liczbą, listą, lambdą czy obiektem klasy Argmhbl. Dba tylko o odpowiedź mylist1 na pytania protokołu. I oczywiście mylist1 odpowiada 5 na pytanie o długość, więc i zwraca mylist2. I to wszystko. Nie ma to nic wspólnego z elementami mylist1 i mylist2 - nigdzie nie pojawiają się na obrazku.Drugi przykład:
&
onlist
Z drugiej strony
&
jest operatorem jak każdy inny, jak+
np. Można go zdefiniować dla typu, definiując specjalną metodę dla tej klasy.int
definiuje to jako bitowe „i”, a bool definiuje jako logiczne „i”, ale to tylko jedna opcja: na przykład zbiory i niektóre inne obiekty, takie jak widoki kluczy dykt, definiują to jako zestaw przecięcia.list
po prostu tego nie definiuje, prawdopodobnie dlatego, że Guido nie wymyślił żadnego oczywistego sposobu zdefiniowania tego.tępy
Z drugiej strony: -D, tablice numpy są wyjątkowe, a przynajmniej starają się być. Oczywiście numpy.array jest tylko klasą, nie może
and
w żaden sposób nadpisać , więc robi następną najlepszą rzecz: gdy zapytamy „czy jesteś prawdziwy”, numpy.array wywołuje błąd ValueError, skutecznie mówiąc „proszę przeformułować pytanie, mój pogląd na prawdę nie pasuje do twojego modelu ”. (Zwróć uwagę, że wiadomość ValueError nie mówi o tymand
- ponieważ numpy.array nie wie, kto zadaje pytanie; po prostu mówi o prawdzie).Bo
&
to zupełnie inna historia. numpy.array może zdefiniować go tak, jak chce, i definiuje&
spójnie z innymi operatorami: punktowy. Więc w końcu dostajesz to, czego chcesz.HTH,
źródło
Skracające się operatory boolowskie (
and
,or
) nie mogą być nadpisane, ponieważ nie ma satysfakcjonującego sposobu na zrobienie tego bez wprowadzenia nowych funkcji języka lub poświęcenia zwarcia. Jak możesz wiedzieć lub nie, oceniają one pierwszy argument pod kątem jego prawdziwości iw zależności od tej wartości albo oceniają i zwracają drugi argument, albo nie oceniają drugiego argumentu i zwracają pierwszy:Zauważ, że zwracany jest (wynik oceny) rzeczywisty operand, a nie jego wartość prawdziwa.
Jedynym sposobem dostosowania ich zachowania jest przesłonięcie
__nonzero__
(zmiana nazwy na__bool__
w Pythonie 3), dzięki czemu możesz wpływać na to, który operand zostanie zwrócony, ale nie zwracać czegoś innego. Listy (i inne kolekcje) definiuje się jako „prawdziwe”, gdy w ogóle cokolwiek zawierają, i „falsey”, gdy są puste.Tablice NumPy odrzucają to pojęcie: w przypadkach użycia, do których dążą, wspólne są dwa różne pojęcia prawdy: (1) czy którykolwiek element jest prawdziwy i (2) czy wszystkie elementy są prawdziwe. Ponieważ te dwa są całkowicie (i cicho) niekompatybilne, i żaden z nich nie jest wyraźnie bardziej poprawny ani bardziej powszechny, NumPy odmawia zgadywania i wymaga wyraźnego użycia
.any()
lub.all()
.&
i|
(inot
przy okazji) mogą być całkowicie nadpisane, ponieważ nie powodują zwarcia. Mogą w ogóle zwrócić wszystko, gdy są zastępowane, a NumPy dobrze to wykorzystuje do wykonywania operacji elementarnych, tak jak robią to z praktycznie każdą inną operacją skalarną. Z drugiej strony listy nie rozgłaszają operacji na swoich elementach. Tak jakmylist1 - mylist2
nic nie znaczy, amylist1 + mylist2
oznacza coś zupełnie innego, nie ma&
operatora dla list.źródło
[False] or [True]
wartościowanie[False]
i[False] and [True]
wartościowanie[True]
.Przykład 1:
Tak działa operator and .
x i y => jeśli x jest fałszem, to x , w przeciwnym razie y
Innymi słowy, ponieważ
mylist1
nie jestFalse
, wynik wyrażenia tomylist2
. (Tylko puste listy mają wartośćFalse
.)Przykład 2:
&
Operator jest dla bitowego i, jak wspomina. Operacje bitowe działają tylko na liczbach. Wynikiem a i b jest liczba złożona z jedynek w bitach, które są równe 1 w obu a i b . Na przykład:Łatwiej jest zobaczyć, co się dzieje, używając literału binarnego (te same liczby co powyżej):
Operacje bitowe są koncepcyjnie podobne do operacji logicznych (prawdziwych), ale działają tylko na bitach.
Tak więc, biorąc pod uwagę kilka wypowiedzi na temat mojego samochodu
Logiczne „i” tych dwóch instrukcji to:
Oba są prawdziwe, przynajmniej w przypadku mojego samochodu. Zatem wartość całego stwierdzenia jest logicznie prawdziwa.
Bitowe „i” tych dwóch stwierdzeń jest trochę bardziej mgliste:
Jeśli Python wie, jak przekonwertować instrukcje na wartości liczbowe, zrobi to i obliczy bitowe i dwóch wartości. Może to prowadzić do przekonania, że
&
jest to wymienne zand
, ale tak jak w powyższym przykładzie są to różne rzeczy. Ponadto w przypadku obiektów, których nie można przekonwertować, otrzymasz po prostu plikTypeError
.Przykład 3 i 4:
Numpy implementuje operacje arytmetyczne dla tablic:
Ale nie implementuje operacji logicznych dla tablic, ponieważ nie można przeciążać operatorów logicznych w Pythonie . Dlatego przykład trzeci nie działa, ale przykład czwarty działa.
Tak, aby odpowiedzieć na Twoje
and
vs&
pytanie: Użyjand
.Operacje bitowe służą do badania struktury liczby (które bity są ustawione, a które nie). Tego rodzaju informacje są najczęściej używane w niskopoziomowych interfejsach systemu operacyjnego ( na przykład bity uprawnień unix ). Większość programów w Pythonie nie musi o tym wiedzieć.
Operacje logiczne (
and
,or
,not
), jednak są wykorzystywane przez cały czas.źródło
W Pythonie wyrażenie
X and Y
zwracaY
, przyjmując, żebool(X) == True
lub którykolwiek zX
lubY
oceniany na False, np .:Operator bitowy po prostu nie jest zdefiniowany dla list. Ale jest zdefiniowany dla liczb całkowitych - operując na binarnej reprezentacji liczb. Rozważmy 16 (01000) i 31 (11111):
NumPy nie jest medium, nie wie, czy masz na myśli, że np.
[False, False]
Powinno być równeTrue
w logicznym wyrażeniu. W tym przypadku zastępuje standardowe zachowanie Pythona, które brzmi: „Dowolna pusta kolekcja zawierającalen(collection) == 0
toFalse
”.Prawdopodobnie oczekiwane zachowanie operatora & tablic NumPy.
źródło
Dla pierwszego przykładu i bazuje na dokumencie django
Zawsze zwróci drugą listę, w rzeczywistości niepusta lista jest postrzegana jako wartość True dla Pythona więc python zwraca 'ostatnią' wartość True, więc druga lista
źródło
Operacje na liście Pythona działają na liście .
list1 and list2
sprawdzi, czylist1
jest pusta, i zwróci,list1
jeśli jest, alist2
jeśli nie.list1 + list2
dołączylist2
dolist1
, więc otrzymasz nową listę zlen(list1) + len(list2)
elementami.Operatory, które mają sens tylko wtedy, gdy są stosowane w odniesieniu do elementów, takie jak
&
podnoszenie aTypeError
, ponieważ operacje na elementach nie są obsługiwane bez zapętlania elementów.Tablice Numpy obsługują operacje elementarne .
array1 & array2
obliczy bitowo lub dla każdego odpowiedniego elementu warray1
iarray2
.array1 + array2
obliczy sumę dla każdego odpowiedniego elementu warray1
iarray2
.To nie działa w przypadku
and
ior
.array1 and array2
jest w zasadzie skrótem dla następującego kodu:W tym celu potrzebujesz dobrej definicji
bool(array1)
. W przypadku operacji globalnych, takich jak używane na listach Pythona, definicja jestbool(list) == True
taka, że jeślilist
nie jest puste, aFalse
jeśli jest puste. W przypadku operacji numpy na elementach istnieje pewna niejednoznaczność, czy należy sprawdzić, czy jakikolwiek element ma wartośćTrue
, czy wszystkie elementy mają wartośćTrue
. Ponieważ oba są prawdopodobnie poprawne, numpy nie zgaduje i zgłaszaValueError
kiedybool()
jest (pośrednio) wywoływane na tablicy.źródło
Dobre pytanie. Podobnie jak w przypadku obserwacji, które masz na temat przykładów 1 i 4 (lub powinienem powiedzieć 1 i 4 :)) z logicznymi operatorami
and
bitowymi&
, doświadczyłem nasum
operatorze. Numpysum
i py równieżsum
zachowują się inaczej. Na przykład:Załóżmy, że „mat” to tablica numpy 5x5 2D, na przykład:
Następnie numpy.sum (mat) daje całkowitą sumę całej macierzy. Natomiast suma wbudowana z Pythona, taka jak sum (mat), sumuje się tylko wzdłuż osi. Zobacz poniżej:
źródło