'and' (boolean) vs '&' (bitwise) - Mengapa perbedaan perilaku dengan daftar vs array numpy?

142

Apa yang menjelaskan perbedaan perilaku operasi boolean dan bitwise pada daftar vs array NumPy?

Saya bingung tentang penggunaan yang tepat dari &vs anddi Python, diilustrasikan dalam contoh berikut.

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!

Jawaban ini dan jawaban ini membantu saya memahami bahwa andini adalah operasi boolean tetapi &operasi bitwise.

Saya membaca tentang operasi bitwise untuk lebih memahami konsep, tetapi saya berjuang untuk menggunakan informasi itu untuk memahami 4 contoh di atas.

Contoh 4 menuntun saya untuk output saya diinginkan, sehingga baik-baik saja, tapi aku masih bingung tentang kapan / bagaimana / mengapa saya harus menggunakan andvs &. Mengapa daftar dan array NumPy berperilaku berbeda dengan operator ini?

Adakah yang bisa membantu saya memahami perbedaan antara operasi boolean dan bitwise untuk menjelaskan mengapa mereka menangani daftar dan array NumPy secara berbeda?

rysqui
sumber
2
Di Numpy ada np.bitwise_and()dan np.logical_and()dan teman-teman untuk menghindari kebingungan.
Dietrich
1
Dalam contoh 1, mylist1 and mylist2tidak menampilkan hasil yang sama dengan mylist2 and mylist1, karena apa yang dikembalikan adalah daftar kedua seperti yang ditunjukkan oleh delnan.
user2015487
1
Kemungkinan duplikat Python: operator Boolean vs operator Bitwise
Oliver Ni

Jawaban:

113

andmenguji apakah kedua ekspresi secara logis Truesementara &(ketika digunakan dengan True/ Falsenilai) menguji apakah keduanya True.

Dalam Python, objek bawaan yang kosong biasanya diperlakukan secara logis Falsesedangkan bawaan yang tidak kosong secara logis True. Ini memfasilitasi kasus penggunaan umum di mana Anda ingin melakukan sesuatu jika daftar kosong dan sesuatu yang lain jika daftar tidak. Perhatikan bahwa ini berarti bahwa daftar [Salah] secara logis True:

>>> if [False]:
...    print 'True'
...
True

Jadi dalam Contoh 1, daftar pertama adalah kosong dan karenanya logis True, sehingga nilai kebenarannya andsama dengan daftar kedua. (Dalam kasus kami, daftar kedua tidak kosong dan karenanya secara logis True, tetapi mengidentifikasi yang memerlukan langkah perhitungan yang tidak perlu.)

Sebagai contoh 2, daftar tidak dapat digabungkan secara bermakna dalam cara bitwise karena mereka dapat mengandung unsur-unsur tidak seperti sewenang-wenang. Hal-hal yang dapat digabungkan dengan bitwise meliputi: Trues and Falses, integer.

Objek NumPy, sebaliknya, mendukung perhitungan vektor. Yaitu, mereka memungkinkan Anda melakukan operasi yang sama pada banyak bagian data.

Contoh 3 gagal karena array NumPy (panjang> 1) tidak memiliki nilai kebenaran karena ini mencegah kebingungan logika berbasis vektor.

Contoh 4 hanyalah andoperasi bit vektor .

Intinya

  • Jika Anda tidak berurusan dengan array dan tidak melakukan manipulasi matematika bilangan bulat, Anda mungkin ingin and.

  • Jika Anda memiliki vektor nilai kebenaran yang ingin Anda gabungkan, gunakan numpydengan &.

ramcdougal
sumber
26

Tentang list

Pertama, poin yang sangat penting, dari mana semuanya akan mengikuti (saya harap).

Dalam Python biasa, listtidak khusus dengan cara apa pun (kecuali memiliki sintaks lucu untuk membangun, yang sebagian besar merupakan kecelakaan historis). Setelah daftar [3,2,6]dibuat, itu untuk semua maksud dan tujuan hanya objek Python biasa, seperti angka 3, set {3,7}, atau fungsi lambda x: x+5.

(Ya, ia mendukung pengubahan elemen-elemennya, dan mendukung iterasi, dan banyak hal lainnya, tetapi itulah jenisnya: ia mendukung beberapa operasi, sementara tidak mendukung beberapa yang lain. Int mendukung peningkatan daya, tetapi itu tidak buat itu sangat istimewa - itu hanya int. lambda mendukung pemanggilan, tapi itu tidak membuatnya sangat istimewa - itulah gunanya lambda :)

Tentang and

andbukan operator (Anda dapat menyebutnya "operator", tetapi Anda dapat memanggil "untuk" operator juga :). Operator di Python adalah (diimplementasikan melalui) metode yang dipanggil pada objek dari beberapa jenis, biasanya ditulis sebagai bagian dari jenis itu. Tidak ada cara bagi suatu metode untuk mengadakan evaluasi terhadap beberapa operandnya, tetapi anddapat (dan harus) melakukannya.

Konsekuensi dari itu adalah bahwa andtidak dapat kelebihan beban, sama seperti fortidak dapat kelebihan beban. Ini sepenuhnya umum, dan berkomunikasi melalui protokol yang ditentukan. Yang dapat Anda lakukan adalah menyesuaikan bagian protokol Anda, tetapi itu tidak berarti Anda dapat mengubah perilaku andsepenuhnya. Protokolnya adalah:

Bayangkan Python menafsirkan "a dan b" (ini tidak terjadi secara harfiah seperti ini, tetapi membantu memahami). Ketika datang ke "dan", itu melihat objek yang baru saja dievaluasi (a), dan bertanya: apakah Anda benar? ( BUKAN : apakah Anda True?) Jika Anda seorang penulis kelas a, Anda dapat menyesuaikan jawaban ini. Jika ajawaban "tidak", and(melompati b sepenuhnya, itu tidak dievaluasi sama sekali, dan) mengatakan: aadalah hasil saya ( BUKAN : Salah adalah hasil saya).

Jika atidak menjawab, andtanyakan: berapa panjang Anda? (Sekali lagi, Anda dapat menyesuaikan ini sebagai penulis akelas). Jika ajawaban 0, andlakukan hal yang sama seperti di atas - menganggapnya salah ( BUKAN Salah), lewati b, dan berikan ahasilnya.

Jika amenjawab sesuatu selain 0 untuk pertanyaan kedua ("berapa panjang Anda"), atau tidak menjawab sama sekali, atau menjawab "ya" untuk pertanyaan pertama ("apakah Anda benar"), andmengevaluasi b, dan mengatakan: badalah hasil saya. Perhatikan bahwa ia TIDAK mengajukan bpertanyaan apa pun.

Cara lain untuk mengatakan semua ini a and badalah hampir sama dengan b if a else a, kecuali a dievaluasi hanya sekali.

Sekarang duduk selama beberapa menit dengan pena dan kertas, dan yakinkan diri Anda bahwa ketika {a, b} adalah himpunan bagian dari {Benar, Salah}, itu berfungsi persis seperti yang Anda harapkan dari operator Boolean. Tetapi saya harap saya telah meyakinkan Anda bahwa itu jauh lebih umum, dan seperti yang akan Anda lihat, jauh lebih bermanfaat dengan cara ini.

Menyatukan keduanya

Sekarang saya harap Anda memahami contoh Anda 1. andtidak peduli apakah mylist1 adalah angka, daftar, lambda atau objek dari kelas Argmhbl. Itu hanya peduli tentang jawaban mylist1 untuk pertanyaan-pertanyaan protokol. Dan tentu saja, mylist1 menjawab 5 pertanyaan tentang panjang, jadi dan mengembalikan mylist2. Dan itu saja. Ini tidak ada hubungannya dengan elemen mylist1 dan mylist2 - mereka tidak memasukkan gambar di mana pun.

Contoh kedua: &padalist

Di sisi lain, &adalah operator seperti yang lain, seperti +misalnya. Itu dapat didefinisikan untuk tipe dengan mendefinisikan metode khusus pada kelas itu. intmendefinisikannya sebagai bitwise "dan", dan bool mendefinisikannya sebagai logis "dan", tetapi itu hanya satu opsi: misalnya, set dan beberapa objek lain seperti tampilan kunci dict mendefinisikannya sebagai persimpangan set. listtidak mendefinisikannya, mungkin karena Guido tidak memikirkan cara yang jelas untuk mendefinisikannya.

numpy

Di sisi lain: -D, array numpy adalah spesial, atau setidaknya mereka berusaha menjadi. Tentu saja, numpy.array hanya sebuah kelas, ia tidak dapat menimpa anddengan cara apa pun, sehingga ia melakukan hal terbaik berikutnya: ketika ditanya "apakah Anda benar", numpy.array meningkatkan ValueError, secara efektif mengatakan "tolong ulangi pertanyaannya, saya pandangan kebenaran tidak cocok dengan model Anda ". (Perhatikan bahwa pesan ValueError tidak berbicara tentang and- karena numpy.array tidak tahu siapa yang menanyakannya; itu hanya berbicara tentang kebenaran.)

Sebab &, ceritanya sangat berbeda. numpy.array dapat mendefinisikannya seperti yang diinginkan, dan mendefinisikan &secara konsisten dengan operator lain: pointwise. Jadi Anda akhirnya mendapatkan apa yang Anda inginkan.

HTH,

Veky
sumber
23

Operator boolean hubungan pendek ( and, or) tidak dapat diganti karena tidak ada cara yang memuaskan untuk melakukan ini tanpa memperkenalkan fitur bahasa baru atau mengorbankan hubungan pendek. Karena Anda mungkin atau mungkin tidak tahu, mereka mengevaluasi operan pertama untuk nilai kebenarannya, dan tergantung pada nilai itu, apakah mengevaluasi dan mengembalikan argumen kedua, atau tidak mengevaluasi argumen kedua dan mengembalikan yang pertama:

something_true and x -> x
something_false and x -> something_false
something_true or x -> something_true
something_false or x -> x

Perhatikan bahwa (hasil mengevaluasi) operan aktual dikembalikan, bukan nilai kebenarannya.

Satu-satunya cara untuk menyesuaikan perilaku mereka adalah dengan mengganti __nonzero__(diubah namanya menjadi __bool__Python 3), sehingga Anda dapat memengaruhi operan mana yang dikembalikan, tetapi tidak mengembalikan sesuatu yang berbeda. Daftar (dan koleksi lainnya) didefinisikan sebagai "benar" ketika mengandung apa saja, dan "falsey" ketika kosong.

Array NumPy menolak gagasan itu: Untuk kasus penggunaan yang mereka tuju, dua gagasan kebenaran yang berbeda adalah umum: (1) Apakah elemen apa pun benar, dan (2) apakah semua elemen itu benar. Karena keduanya benar-benar (dan diam-diam) tidak kompatibel, dan tidak ada yang jelas lebih benar atau lebih umum, NumPy menolak untuk menebak dan mengharuskan Anda untuk secara eksplisit menggunakan .any()atau .all().

&dan |(dan not, omong-omong) dapat sepenuhnya ditimpa, karena mereka tidak mengalami hubungan pendek. Mereka dapat mengembalikan apa saja ketika ditimpa, dan NumPy memanfaatkannya untuk melakukan operasi elemen-bijaksana, seperti yang mereka lakukan dengan hampir semua operasi skalar lainnya. Daftar, di sisi lain, tidak menyiarkan operasi di seluruh elemen mereka. Sama seperti mylist1 - mylist2tidak berarti apa-apa dan mylist1 + mylist2berarti sesuatu yang sama sekali berbeda, tidak ada &operator untuk daftar.


sumber
3
Salah satu contoh yang sangat menarik dari apa yang dapat dihasilkan ini adalah [False] or [True]dievaluasi [False], dan [False] and [True]dievaluasi [True].
Rob Watts
16

Contoh 1:

Ini adalah bagaimana dan operator.

x dan y => jika x salah, maka x , kalau tidak y

Jadi dengan kata lain, karena mylist1tidak False, hasil dari ekspresi adalah mylist2. (Hanya daftar kosong dievaluasi False.)

Contoh 2:

The &operator adalah untuk bitwise dan, seperti yang Anda sebutkan. Operasi bitwise hanya bekerja pada angka. Hasil dari a & b adalah angka yang terdiri dari 1s dalam bit yaitu 1 pada a dan b . Sebagai contoh:

>>> 3 & 1
1

Lebih mudah untuk melihat apa yang terjadi menggunakan biner literal (angka yang sama seperti di atas):

>>> 0b0011 & 0b0001
0b0001

Operasi bitwise serupa dalam konsepnya dengan operasi boolean (kebenaran), tetapi mereka hanya bekerja pada bit.

Jadi, diberikan beberapa pernyataan tentang mobil saya

  1. Mobil saya merah
  2. Mobil saya memiliki roda

Logika "dan" dari kedua pernyataan ini adalah:

(apakah mobil saya merah?) dan (apakah mobil memiliki roda?) => logical true of false value

Keduanya benar, setidaknya untuk mobil saya. Jadi nilai pernyataan secara keseluruhan adalah logis benar .

Bitwise "dan" dari kedua pernyataan ini sedikit lebih samar:

(nilai numerik pernyataan 'mobil saya merah') & (nilai numerik pernyataan 'mobil saya memiliki roda') => angka

Jika python tahu bagaimana mengubah pernyataan ke nilai numerik, maka ia akan melakukannya dan menghitung bitwise-dan dari dua nilai. Ini mungkin membuat Anda percaya bahwa &itu dapat dipertukarkan dengan and, tetapi seperti pada contoh di atas mereka adalah hal yang berbeda. Juga, untuk objek yang tidak dapat dikonversi, Anda hanya akan mendapatkan TypeError.

Contoh 3 dan 4:

Numpy mengimplementasikan operasi aritmatika untuk array:

Operasi aritmatika dan perbandingan pada ndarrays didefinisikan sebagai operasi elemen-bijaksana, dan umumnya menghasilkan objek ndarray sebagai hasilnya.

Tetapi tidak menerapkan operasi logis untuk array, karena Anda tidak dapat membebani operator logis dengan python . Itu sebabnya contoh tiga tidak berfungsi, tetapi contoh empat tidak.

Jadi untuk menjawab pertanyaan andvs Anda &: Gunakanand .

Operasi bitwise digunakan untuk memeriksa struktur angka (bit mana yang diset, bit mana yang tidak disetel). Informasi semacam ini sebagian besar digunakan dalam antarmuka sistem operasi tingkat rendah ( unix bits bits) ). Sebagian besar program python tidak perlu tahu itu.

Operasi logis ( and, or, not), bagaimanapun, digunakan sepanjang waktu.

Seth
sumber
14
  1. Dalam Python ekspresi X and Ypengembalian Y, mengingat itu bool(X) == Trueatau salah satu Xatau Ymengevaluasi ke False, misalnya:

    True and 20 
    >>> 20
    
    False and 20
    >>> False
    
    20 and []
    >>> []
  2. Operator bitwise sama sekali tidak ditentukan untuk daftar. Tapi itu didefinisikan untuk bilangan bulat - beroperasi atas representasi biner dari angka-angka. Pertimbangkan 16 (01000) dan 31 (11111):

    16 & 31
    >>> 16
  3. NumPy bukan seorang paranormal, ia tidak tahu, apakah maksud Anda misalnya [False, False]harus sama dengan Truedalam ekspresi logis. Dalam ini menimpa perilaku Python standar, yaitu: "Setiap koleksi kosong len(collection) == 0adalah False".

  4. Mungkin perilaku yang diharapkan dari array & operator NumPy.

Zaur Nasibov
sumber
False dan 20 mengembalikan False
Rahul
4

Untuk contoh pertama dan berdasarkan pada dokumen Django itu
akan selalu mengembalikan daftar kedua, memang daftar yang tidak kosong dilihat sebagai nilai True untuk Python sehingga python mengembalikan nilai True 'terakhir' sehingga daftar kedua

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]
MoiTux
sumber
4

Operasi dengan daftar Python beroperasi pada daftar . list1 and list2akan memeriksa apakah list1kosong, dan kembali list1jika ada, dan list2jika tidak. list1 + list2akan ditambahkan list2ke list1, sehingga Anda mendapatkan daftar baru dengan len(list1) + len(list2)elemen.

Operator yang hanya masuk akal ketika elemen diterapkan, seperti &, meningkatkan a TypeError, karena operasi elemen-bijaksana tidak didukung tanpa perulangan melalui elemen.

Array numpy mendukung operasi elemen-bijaksana . array1 & array2akan menghitung bitwise atau untuk setiap elemen yang sesuai di array1dan array2. array1 + array2akan menghitung jumlah untuk setiap elemen yang sesuai di array1dan array2.

Ini tidak berfungsi untuk anddan or.

array1 and array2 pada dasarnya adalah kependekan dari kode berikut:

if bool(array1):
    return array2
else:
    return array1

Untuk ini, Anda perlu definisi yang baik tentang bool(array1). Untuk operasi global seperti yang digunakan pada daftar Python, definisi adalah bahwa bool(list) == Truejika listtidak kosong, dan Falsejika kosong. Untuk operasi elemen-bijaksana numpy, ada beberapa ketidakjelasan apakah untuk memeriksa apakah elemen mengevaluasi True, atau semua elemen mengevaluasi True. Karena keduanya bisa dibilang benar, numpy tidak menebak dan memunculkan ValueErrorkapan bool()(secara tidak langsung) dipanggil pada array.

knbk
sumber
0

Pertanyaan bagus. Mirip dengan pengamatan yang Anda miliki tentang contoh 1 dan 4 (atau harus saya katakan 1 & 4 :)) lebih dari operator andbitwise logis &, saya alami pada sumoperator. Numpy sumdan pysum berperilaku berbeda juga. Sebagai contoh:

Misalkan "mat" adalah array 2d 5x5 numpy seperti:

array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20],
       [21, 22, 23, 24, 25]])

Kemudian numpy.sum (mat) memberikan jumlah total dari seluruh matriks. Sedangkan jumlah bawaan dari Python seperti jumlah (tikar) total sepanjang sumbu saja. Lihat di bawah:

np.sum(mat)  ## --> gives 325
sum(mat)     ## --> gives array([55, 60, 65, 70, 75])
SSPrabhu
sumber