Apa perbedaan antara dua baris kode ini:
if not x == 'val':
dan
if x != 'val':
Apakah yang satu lebih efisien daripada yang lain?
Apakah lebih baik digunakan
if x == 'val':
pass
else:
Apa perbedaan antara dua baris kode ini:
if not x == 'val':
dan
if x != 'val':
Apakah yang satu lebih efisien daripada yang lain?
Apakah lebih baik digunakan
if x == 'val':
pass
else:
Jawaban:
Menggunakan dis
untuk melihat bytecode yang dihasilkan untuk dua versi:
not ==
4 0 LOAD_FAST 0 (foo)
3 LOAD_FAST 1 (bar)
6 COMPARE_OP 2 (==)
9 UNARY_NOT
10 RETURN_VALUE
!=
4 0 LOAD_FAST 0 (foo)
3 LOAD_FAST 1 (bar)
6 COMPARE_OP 3 (!=)
9 RETURN_VALUE
Yang terakhir memiliki operasi lebih sedikit, dan karena itu cenderung sedikit lebih efisien
Itu ditunjukkan dalam komitmen (terima kasih, @ Quincunx ) bahwa di mana Anda memiliki if foo != bar
vs if not foo == bar
jumlah operasi persis sama, hanya saja COMPARE_OP
perubahan dan POP_JUMP_IF_TRUE
beralih ke POP_JUMP_IF_FALSE
:
not ==
:
2 0 LOAD_FAST 0 (foo)
3 LOAD_FAST 1 (bar)
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_TRUE 16
!=
2 0 LOAD_FAST 0 (foo)
3 LOAD_FAST 1 (bar)
6 COMPARE_OP 3 (!=)
9 POP_JUMP_IF_FALSE 16
Dalam hal ini, kecuali ada perbedaan dalam jumlah pekerjaan yang diperlukan untuk setiap perbandingan, kecil kemungkinan Anda akan melihat perbedaan kinerja sama sekali.
Namun, perhatikan bahwa kedua versi tidak akan selalu identik secara logis , karena akan tergantung pada implementasi dari __eq__
dan __ne__
untuk objek yang dimaksud. Per dokumentasi model data :
Tidak ada hubungan yang tersirat di antara operator pembanding. Kebenaran
x==y
tidak menyiratkan bahwax!=y
itu salah.
Sebagai contoh:
>>> class Dummy(object):
def __eq__(self, other):
return True
def __ne__(self, other):
return True
>>> not Dummy() == Dummy()
False
>>> Dummy() != Dummy()
True
Akhirnya, dan mungkin yang paling penting: secara umum, di mana dua yang logis identik, x != y
jauh lebih mudah dibaca daripadanot x == y
.
__eq__
tidak konsisten dengan __ne__
itu benar-benar rusak.
not x == y
memiliki satu instruksi lagi. Ketika saya memasukkan kode ke dalam if
, ternyata mereka berdua memiliki jumlah instruksi yang sama, hanya satu yang memiliki POP_JUMP_IF_TRUE
dan yang lainnya POP_JUMP_IF_FALSE
(itu adalah satu-satunya perbedaan di antara mereka, selain menggunakan yang berbeda COMPARE_OP
). Ketika saya mengkompilasi kode tanpa if
s, saya mendapatkan apa yang Anda dapatkan.
==
dan !=
tidak saling eksklusif adalah implementasi SQL-seperti yang melibatkan null
nilai - nilai. Dalam SQL null
tidak kembali true
ke !=
dibandingkan dengan nilai lain, sehingga implementasi python interface SQL mungkin juga memiliki masalah yang sama.
not ==
dan !=
, sepertinya itu menjadi bagian paling menarik dari jawabanku! Saya tidak berpikir ini adalah tempat untuk memikirkan jika, mengapa dan kapan itu masuk akal - lihat misalnya Mengapa Python memiliki __ne__
metode operator bukan hanya __eq__
?
@jonrsharpe memiliki penjelasan yang bagus tentang apa yang terjadi. Saya pikir saya hanya akan menunjukkan perbedaan waktu ketika menjalankan masing-masing dari 3 opsi 10.000.000 kali (cukup untuk menunjukkan sedikit perbedaan).
Kode yang digunakan:
def a(x):
if x != 'val':
pass
def b(x):
if not x == 'val':
pass
def c(x):
if x == 'val':
pass
else:
pass
x = 1
for i in range(10000000):
a(x)
b(x)
c(x)
Dan profil profil cProfile:
Jadi kita dapat melihat bahwa ada perbedaan sangat kecil ~ 0,7% antara if not x == 'val':
dan if x != 'val':
. Dari jumlah tersebut, if x != 'val':
adalah yang tercepat.
Namun, yang paling mengejutkan, kita bisa melihatnya
if x == 'val':
pass
else:
sebenarnya yang tercepat, dan berdetak if x != 'val':
~ 0,3%. Ini tidak terlalu mudah dibaca, tetapi saya kira jika Anda menginginkan peningkatan kinerja yang dapat diabaikan, orang dapat menempuh rute ini.
Dalam yang pertama Python harus menjalankan satu operasi lebih dari yang diperlukan (bukan hanya memeriksa tidak sama dengan itu harus memeriksa apakah itu tidak benar bahwa itu sama, dengan demikian satu operasi lagi). Tidak mungkin mengatakan perbedaan dari satu eksekusi, tetapi jika dijalankan berkali-kali, yang kedua akan lebih efisien. Secara keseluruhan saya akan menggunakan yang kedua, tetapi secara matematis keduanya sama
>>> from dis import dis
>>> dis(compile('not 10 == 20', '', 'exec'))
1 0 LOAD_CONST 0 (10)
3 LOAD_CONST 1 (20)
6 COMPARE_OP 2 (==)
9 UNARY_NOT
10 POP_TOP
11 LOAD_CONST 2 (None)
14 RETURN_VALUE
>>> dis(compile('10 != 20', '', 'exec'))
1 0 LOAD_CONST 0 (10)
3 LOAD_CONST 1 (20)
6 COMPARE_OP 3 (!=)
9 POP_TOP
10 LOAD_CONST 2 (None)
13 RETURN_VALUE
Di sini Anda dapat melihat bahwa not x == y
memiliki satu instruksi lebih dari x != y
. Jadi perbedaan kinerja akan sangat kecil dalam banyak kasus kecuali jika Anda melakukan jutaan perbandingan dan bahkan kemudian ini kemungkinan tidak akan menjadi penyebab kemacetan.
Catatan tambahan, karena jawaban lain menjawab sebagian besar pertanyaan Anda dengan benar, adalah bahwa jika sebuah kelas hanya mendefinisikan __eq__()
dan tidak __ne__()
, maka Anda COMPARE_OP (!=)
akan menjalankan __eq__()
dan meniadakannya. Pada saat itu, opsi ketiga Anda cenderung menjadi sedikit lebih efisien, tetapi seharusnya hanya dipertimbangkan jika Anda MEMBUTUHKAN kecepatan, karena sulit untuk dipahami dengan cepat.
Ini tentang cara Anda membacanya. not
operator itu dinamis, itu sebabnya Anda bisa menerapkannya
if not x == 'val':
Tetapi !=
dapat dibaca dalam konteks yang lebih baik sebagai operator yang melakukan kebalikan dari apa yang ==
dilakukan.
not
operator itu dinamis" ?
Saya ingin memperluas komentar keterbacaan saya di atas.
Sekali lagi, saya sepenuhnya setuju dengan keterbacaan yang mengesampingkan masalah lain (kinerja-tidak signifikan).
Yang ingin saya tunjukkan adalah otak mengartikan "positif" lebih cepat daripada "negatif". Misalnya, "berhenti" vs. "jangan pergi" (contoh yang agak buruk karena perbedaan jumlah kata).
Jadi diberi pilihan:
if a == b
(do this)
else
(do that)
lebih disukai daripada yang secara fungsional setara:
if a != b
(do that)
else
(do this)
Kurang mudah dibaca / dimengerti menyebabkan lebih banyak bug. Mungkin tidak dalam pengkodean awal, tetapi pemeliharaan (tidak sepintar Anda!) Berubah ...