Lebih efisien menggunakan if-return-return atau if-else-return?

141

Misalkan saya punya ifpernyataan dengan a return. Dari perspektif efisiensi, harus saya gunakan

if(A > B):
    return A+1
return A-1

atau

if(A > B):
    return A+1
else:
    return A-1

Haruskah saya lebih suka satu atau yang lain ketika menggunakan bahasa yang dikompilasi (C) atau yang scripted (Python)?

Jorge Leitao
sumber
11
Dalam bahasa yang dikompilasi Anda tidak perlu terlalu khawatir tentang efisiensi. Kompiler mengatasinya. Anda harus menulis kode Anda sehingga Anda dapat membacanya. (Anda masih harus khawatir tentang efisiensi algoritma Anda, dan penggunaan tipe ceroboh dll akan mempengaruhi efisiensi - Anda hanya tidak terlalu khawatir tentang gaya Anda.) Saya tidak tahu tentang Python.
ams
5
Mengandalkan kompiler Anda untuk memilah-milah kode Anda adalah langkah berbahaya - dan membutuhkan kompilator yang sempurna. Lebih baik jika Anda tahu bagaimana Anda ingin kode Anda lakukan!
Andrew
1
Jika apa yang Anda lakukan didefinisikan oleh spec, maka saya tidak percaya ada alasan untuk meragukan kompiler. Itu akan ditulis sebagai orang yang jauh lebih pintar daripada Anda, dan itu jauh lebih mungkin bahwa Anda membuat kesalahan daripada mereka.
Akan
7
Bagaimana ini bisa ditutup berdasarkan opini? Mungkin ada pendapat setelah Anda tahu bahwa tidak ada perbedaan kinerja antara keduanya. Saya tidak, dan saya cukup yakin bahwa banyak orang juga tidak.
Jorge Leitao
1
Meskipun pertanyaannya cukup populer, ia tidak dapat dijawab secara akurat tanpa mengingat bahasa tertentu, atau jika tidak, menjawab untuk setiap bahasa akan terlalu lama untuk format ini.
Emile Bergeron

Jawaban:

195

Karena returnpernyataan tersebut mengakhiri eksekusi dari fungsi saat ini, kedua bentuk itu setara (walaupun yang kedua bisa dibilang lebih mudah dibaca daripada yang pertama).

Efisiensi kedua bentuk ini sebanding, kode mesin yang mendasarinya harus melakukan lompatan jika ifkondisinya salah.

Perhatikan bahwa Python mendukung sintaks yang memungkinkan Anda untuk menggunakan hanya satu returnpernyataan dalam kasus Anda:

return A+1 if A > B else A-1
Frédéric Hamidi
sumber
32
C juga mendukung itu. return (A>B)?A+1:A-1;Namun sama sekali tidak ada keuntungan dalam kinerja dari penulisan kode seperti ini. Semua yang kami raih adalah membuat kode tersebut dikaburkan, tidak terbaca, dan dalam beberapa kasus lebih rentan terhadap promosi jenis tersirat.
Lundin
47
@Lundin dikaburkan? tidak terbaca? Hanya untuk mereka yang tidak tahu operator ternary.
glglgl
6
@Lundin Mengikuti argumentasi ini, <adalah praktik buruk karena -1 < 1umenghasilkan hasil yang tidak terduga.
glglgl
3
@glglgl: Tidak, karena orang-orang mengharapkan operator: berperilaku seolah-olah, yang tidak benar. Jika seseorang akan menulis kode seperti -1 < 1u, yang saya ragu, mereka akan dengan mudah menemukan bug. Cukup banyak orang akan menulis beberapa versi dari kode yang saya posting. Saya sudah terlalu sering melihat bug seperti itu dalam kode produksi untuk memercayai operator? Sebagai aturan umum, jika bahasa tersebut memberi Anda dua cara berbeda untuk melakukan hal yang sama, hanya gunakan salah satunya, jangan memilih salah satu dari keduanya secara acak tergantung pada suasana hati Anda.
Lundin
6
@Lundin itu adalah argumen untuk berhati-hati?: Di C, tetapi Anda tampaknya mengatakan itu berlaku untuk Python juga. Bisakah Anda tunjukkan contoh mana pun yang menggunakan terner di Python mengarah ke hasil yang tidak terduga?
Lvc
33

Dari panduan gaya Chromium :

Jangan gunakan yang lain setelah kembali:

# Bad
if (foo)
  return 1
else
  return 2

# Good
if (foo)
  return 1
return 2

return 1 if foo else 2
skeller88
sumber
1
Terima kasih. +1. Bolehkah saya bertanya mengapa tidak menggunakan yang lain setelah kembali?
Tim
1
jika-lain secara fungsional setara, tapi itu bertele-tele. Yang lain tidak perlu.
skeller88
17
Saya terkejut karena yang pertama tampak lebih jelas dan karenanya lebih baik.
Tim
4
Anda bisa membuat alasan yang masuk akal untuk keduanya. Yang paling penting dalam keputusan ini IMO adalah konsisten dalam basis kode.
skeller88
2
Anda mungkin akan menemukan di sebagian besar kasus bahwa if-else-returncabang hampir tidak pernah sama (jika ya, maka Anda harus tetap melakukan refactoring; baik menggunakan switchkonstruk atau untuk Python, menghitung dict / menggunakan callable / etc.). Oleh karena itu hampir semua if-else-returnkasus klausa penjaga dan mereka selalu dapat diuji (mengejek ekspresi yang diuji) tanpa else.
cowbert
5

Mengenai gaya pengkodean:

Sebagian besar standar pengkodean tidak peduli bahasa melarang pernyataan pengembalian berulang dari satu fungsi sebagai praktik buruk.

(Meskipun secara pribadi saya akan mengatakan ada beberapa kasus di mana beberapa pernyataan kembali masuk akal: teks / parser protokol data, fungsi dengan penanganan kesalahan yang luas, dll)

Konsensus dari semua standar pengkodean industri tersebut adalah bahwa ekspresi harus ditulis sebagai:

int result;

if(A > B)
{
  result = A+1;
}
else
{
  result = A-1;
}
return result;

Mengenai efisiensi:

Contoh di atas dan dua contoh dalam pertanyaan semuanya sepenuhnya setara dalam hal efisiensi. Kode mesin dalam semua kasus ini harus membandingkan A> B, kemudian bercabang dengan perhitungan A + 1 atau A-1, kemudian menyimpan hasilnya di register CPU atau di stack.

EDIT:

Sumber:

  • MISRA-C: 2004 aturan 14.7, yang pada gilirannya mengutip ...:
  • IEC 61508-3. Bagian 3, tabel B.9.
  • IEC 61508-7. C.2.9.
Lundin
sumber
37
Apakah Anda yakin agama satu-kembali telah menginfeksi sebagian besar standar pengkodean? Itu akan menakutkan.
Daniel Fischer
7
Saya akan mengatakan aturan itu tidak masuk akal sebagian besar waktu. Saya cenderung menemukan kode lebih mudah dibaca dan lebih mudah diikuti dengan pengembalian pada poin yang sesuai. Tapi itu hanya aku. Namun, saya memikirkan standar pengkodean perusahaan / proyek, bukan hal-hal seperti MISRA di mana resep idiot kadang-kadang memiliki beberapa kelebihan. Saya harap sebagian besar tidak setuju dengan ide titik keluar tunggal.
Daniel Fischer
3
@DanielFischer: Dalam standar pengkodean C berdasarkan MISRA yang saya rancang untuk perusahaan saya, saya memiliki aturan "Suatu fungsi hanya akan memiliki satu titik keluar, pada akhir fungsi, kecuali satu titik keluar membuat kode kurang terbaca ". Jadi itu MISRA-C tetapi dengan pengecualian aturan. Jika Anda menulis fungsi parser tingkat lanjut yang dapat mengembalikan katakanlah 10 kesalahan berbeda, tingkat kawat bersarang membuat kode benar-benar tidak dapat dibaca - dalam kasus seperti itu akan lebih masuk akal untuk segera kembali ketika kesalahan terjadi.
Lundin
6
Lihat pertanyaan SO ini untuk diskusi dan tautan lebih lanjut ke diskusi lebih lanjut tentang masalah titik keluar tunggal. Selain aturan titik keluar tunggal yang kuno dan terlalu "rekayasa", Python secara khusus mempromosikan tampilan "flat lebih baik daripada bersarang" , dan menempatkan di return mana pun itu menjadi jelas adalah cara idiomatis untuk melakukannya dengan Python.
John Y
1
@percebus Saya sepenuhnya setuju dan kompleksitas siklomatik adalah argumen yang bagus untuk menentang pengembalian tunggal. Dan saya telah menyodok komite MISRA tentang ini beberapa kali, misalnya melihat ini . Setidaknya aturan diturunkan menjadi penasihat dalam MISRA-C: 2012.
Lundin
3

Dengan kompiler yang masuk akal, Anda seharusnya tidak melihat perbedaan; mereka harus dikompilasi ke kode mesin identik karena mereka setara.

Oliver Charlesworth
sumber
2

Ini adalah masalah gaya (atau preferensi) karena penerjemah tidak peduli. Secara pribadi saya akan mencoba untuk tidak membuat pernyataan akhir dari suatu fungsi yang mengembalikan nilai pada level indent selain dari basis fungsi. Yang lain dalam contoh 1 mengaburkan, jika hanya sedikit, di mana akhir fungsi.

Menurut preferensi saya menggunakan:

return A+1 if (A > B) else A-1

Karena ia mematuhi baik konvensi yang baik untuk memiliki pernyataan pengembalian tunggal sebagai pernyataan terakhir dalam fungsi (sebagaimana telah disebutkan) dan paradigma pemrograman fungsional yang baik untuk menghindari hasil-hasil antara gaya imperatif.

Untuk fungsi yang lebih kompleks, saya lebih suka memecah fungsi menjadi beberapa sub-fungsi untuk menghindari pengembalian prematur jika memungkinkan. Kalau tidak, saya kembali menggunakan variabel gaya imperatif yang disebut rval. Saya mencoba untuk tidak menggunakan banyak pernyataan pengembalian kecuali fungsinya sepele atau pernyataan kembali sebelum akhir adalah sebagai akibat dari kesalahan. Mengembalikan prematur menyoroti fakta bahwa Anda tidak dapat melanjutkan. Untuk fungsi kompleks yang dirancang untuk bercabang menjadi beberapa subfungsi saya mencoba untuk mengkodekannya sebagai pernyataan kasus (didorong oleh dict misalnya).

Beberapa poster menyebutkan kecepatan operasi. Kecepatan Jalankan adalah waktu yang kedua bagi saya karena jika Anda memerlukan kecepatan eksekusi, Python bukan bahasa terbaik untuk digunakan. Saya menggunakan Python sebagai efisiensi pengkodean (yaitu menulis kode bebas kesalahan) yang penting bagi saya.

Stephen Ellwood
sumber
1
Jika seorang pengguna akan memilih-bawah jawaban saya, saya akan sangat menghargai komentar mengapa mereka berpikir saya salah.
Stephen Ellwood
Saya mungkin akan hanya satu baris sebelumnya untuk membuatnya 1 baris per pernyataan untuk tujuan keterbacaan. var n = 1 if (A > B) else -1 return A+n
percebus
@percebus dalam beberapa kasus saya akan setuju jika nama variabel dapat meningkatkan maknanya. Misalnya: 'kode' move_x = 1 jika my_x <lawan_x lain -1 # bergerak ke arah lawan
Stephen Ellwood
BTW, aku benar-benar mengangkat jawaban Anda. Jika Anda melihat jawaban saya agak mirip
percebus
2

Saya pribadi menghindari elseblok jika memungkinkan. Lihat Kampanye Anti-jika

Juga, mereka tidak mengenakan biaya 'ekstra' untuk saluran, Anda tahu: hal

"Sederhana lebih baik daripada kompleks" & "Keterbacaan adalah raja"

delta = 1 if (A > B) else -1
return A + delta
percebus
sumber
2
Mengapa memilih bawah? Adalah jawaban 'pythonic'. Anda mungkin tidak menganggapnya sebagai jawaban yang disukai. Tetapi bukan yang tidak valid. Saya juga mengikuti Prinsip KISS en.wikipedia.org/wiki/KISS_principle
percebus
3
Saya mengubah jawaban Anda karena bagi saya skor pada keterbacaan dan sederhana. Saya pribadi merasa ofensif adalah seseorang yang memilih saya tanpa mendidik saya mengapa jawaban saya negatif.
Stephen Ellwood
1
Tidak pernah mendengar sebelumnya tentang kampanye Anti-jika tetapi dapat memahami mengapa jika bisa berbahaya. Saya selalu mencoba membatasi jumlah kode yang dilampirkan oleh pernyataan if dan mencoba untuk menulis ulang pohon elif untuk menggunakan dict. Ini semakin sedikit di luar topik.
Stephen Ellwood
1
@StephenEllwood Menggunakan dicts untuk menghindari perbedaan adalah ide yang sangat buruk untuk kinerja.
Bachsau
@ Bachsau Anda mungkin benar. Saya tidak pernah khawatir tentang kinerja karena semua skrip saya berjalan dalam hitungan detik. Bagi saya keterbacaan biasanya mengalahkan kinerja. Karena saya bukan programmer penuh waktu; mereka hanyalah sarana untuk mencapai tujuan.
Stephen Ellwood
1

Versi A lebih sederhana dan itu sebabnya saya akan menggunakannya.

Dan jika Anda mengaktifkan semua peringatan kompiler di Jawa Anda akan mendapatkan peringatan pada Versi kedua karena itu tidak perlu dan ternyata kompleksitas kode.

juergen d
sumber
1

Saya tahu pertanyaan ini ditandai dengan python, tetapi ia menyebutkan bahasa yang dinamis jadi saya pikir saya harus menyebutkan bahwa di ruby ​​pernyataan if sebenarnya memiliki tipe pengembalian sehingga Anda dapat melakukan sesuatu seperti

def foo
  rv = if (A > B)
         A+1
       else
         A-1
       end
  return rv 
end

Atau karena ia juga memiliki pengembalian implisit

def foo 
  if (A>B)
    A+1
  else 
    A-1
  end
end

yang mengatasi masalah gaya tidak memiliki beberapa pengembalian dengan cukup baik.

Jamie Cook
sumber