Pertanyaan Kesetimbangan Cek Kesetaraan Python


Misalkan kita ingin beberapa blok kode yang akan dieksekusi ketika 'a' dan 'b' sama dengan mengatakan 5. Kemudian kita dapat menulis seperti:

if a == 5 and b == 5:
    # do something

Tetapi beberapa hari yang lalu, saya hanya secara tidak sengaja menulis cek kondisi yang sama seperti:

if a == b and b == 5:
    # do something 

yang membuat saya berpikir, apakah ada perbedaan antara keduanya? Juga, ada satu cara lain,

if a == b == 5:
    # do something

Apakah ada perbedaan, ada perbedaan dalam hal proses evaluasi atau eksekusi atau waktu yang diambil? dan juga mana yang lebih baik atau mana yang lebih baik untuk digunakan?

Apakah ini terkait dengan konsep transitivitas?


41
2018-04-22 12:50


asal


Jawaban:


Karena mereka pada dasarnya setara, Anda juga dapat mempertimbangkan cara Anda membaca / berpikir tentang kode:

if a == 5 and b == 5:
  # do something

dapat Baca baca seolah-olah a sama 5 dan b sama 5, lalu lakukan ... ". Anda harus pikirkan / simpulkan, itu juga a akan sama dengan b.

Ini berlawanan dengan contoh berikut:

if a == b and b == 5:
  # do something 

Ini dibaca seolah-olah a adalah sama dengan b dan b sama dengan 5"dan kamu harus menyimpulkan itu juga a akan sama dengan 5

Inilah mengapa saya lebih suka contoh terakhir:

if a == b == 5:
  # do something

Jika Anda akrab dengan Python (terimakasih untuk Itzkata) segera jelas bahwa ketiga hal itu harus sama (untuk 5). Namun jika orang dengan pengalaman kurang dalam Python (tetapi keterampilan pemrograman dalam bahasa lain) melihat ini, mereka mungkin mengevaluasi ini

if (a == b) == 5:

yang akan membandingkan hasil boolean dari perbandingan pertama dengan bilangan bulat 5, yang bukan apa yang dilakukan Python dan mungkin mengarah pada hasil yang berbeda (pertimbangkan misalnya dengan a=0, b=0: a==b==0 benar sementara (a==b) == 0 tidak!

Itu manual mengatakan:

Ada delapan operasi perbandingan dengan Python. Mereka semua punya   prioritas yang sama (yang lebih tinggi dari operasi Boolean).   Perbandingan dapat dirantai secara sewenang-wenang; misalnya, x <y <= z adalah   setara dengan x <y dan y <= z, kecuali bahwa y dievaluasi hanya sekali   (tetapi dalam kedua kasus z tidak dievaluasi sama sekali ketika x <y ditemukan   Salah).

Bahkan mungkin ada perbedaan, misalnya jika evaulasi b dalam contoh Anda akan memiliki efek samping.

Mengenai transitivitas, Anda benar.


41
2018-04-22 12:55



Jika Anda memiliki lebih banyak variabel untuk diuji, gunakan all mungkin sedikit lebih mudah dibaca:

if all(i==5 for i in [a,b,c,d]):
    # do something

19
2018-04-22 13:03



Sejauh menyangkut bilangan bulat, tidak ada perbedaan, dalam hal kinerja belaka, antara dua perbandingan pertama.

Perbandingan ketiga berbeda, meskipun; sejak sedikit lebih mengotak-atik tumpukan terlibat. Memang, kode itu

import dis

def comparison_1(a, b):
    if a == 5 and b == 5:
        pass

def comparison_2(a, b):
    if a == b and b == 5:
        pass

def comparison_3(a, b):
    if a == b == 5:
        pass

print("*** First comparison ***")
dis.dis(comparison_1)

print("\n*** Second comparison ***")
dis.dis(comparison_2)

print("\n*** Third comparison ***")
dis.dis(comparison_3)

kembali

*** First comparison ***
  4           0 LOAD_FAST                0 (a)
              3 LOAD_CONST               1 (5)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_FALSE       27
             12 LOAD_FAST                1 (b)
             15 LOAD_CONST               1 (5)
             18 COMPARE_OP               2 (==)
             21 POP_JUMP_IF_FALSE       27

  5          24 JUMP_FORWARD             0 (to 27)
        >>   27 LOAD_CONST               0 (None)
             30 RETURN_VALUE        

*** Second comparison ***
  8           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_FALSE       27
             12 LOAD_FAST                1 (b)
             15 LOAD_CONST               1 (5)
             18 COMPARE_OP               2 (==)
             21 POP_JUMP_IF_FALSE       27

  9          24 JUMP_FORWARD             0 (to 27)
        >>   27 LOAD_CONST               0 (None)
             30 RETURN_VALUE        

*** Third comparison ***
 12           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 DUP_TOP             
              7 ROT_THREE           
              8 COMPARE_OP               2 (==)
             11 JUMP_IF_FALSE_OR_POP    23
             14 LOAD_CONST               1 (5)
             17 COMPARE_OP               2 (==)
             20 JUMP_FORWARD             2 (to 25)
        >>   23 ROT_TWO             
             24 POP_TOP             
        >>   25 POP_JUMP_IF_FALSE       31

 13          28 JUMP_FORWARD             0 (to 31)
        >>   31 LOAD_CONST               0 (None)
             34 RETURN_VALUE        

15
2018-04-22 12:57



Tergantung. Anda dapat menulis kebiasaan Anda sendiri __eq__ yang memungkinkan Anda membandingkan diri Anda dengan int dan hal-hal:

 class NonNegativeInt(object):
   def __init__(self, value):
     if value < 0:
       raise Exception("Hey, what the...")
     self.value = value

   def __eq__(self, that):
     if isinstance(that, int):
       return self.value == that
     elif isinstance(that, NonNegativeInt):
       return self.value == that.value
     else:
       raise ArgumentError("Not an acceptible argument", "__eq__", that)

yang akan bekerja berbeda tergantung pada membandingkan "b" menjadi "a" dan "b" menjadi "int." Karenanya, a == b bisa salah sementara a == 5 and b == 5 bisa jadi Benar.


6
2018-04-22 12:55