Gaya mana yang digunakan untuk parameter pengembalian yang tidak digunakan dalam panggilan fungsi Python

30

Apakah ada gaya pengkodean yang direkomendasikan / diterima secara umum untuk menangani situasi di mana suatu fungsi mengembalikan tupel nilai tetapi hanya satu dari nilai-nilai itu yang digunakan sesudahnya (perhatikan bahwa ini sebagian besar dimaksudkan untuk fungsi pustaka yang tidak dapat saya ubah - menulis pembungkus di sekitar panggilannya mungkin sedikit berlebihan ...)? Alih-alih melakukan

a, b, c = foo()

dan kemudian tidak menggunakan bdan c, mana dari varian berikut harus lebih disukai (atau ada yang lain?):

Varian 1 (garis bawah)

a, _, _ = foo()

(yang sangat jelas dan sederhana tetapi mungkin berbenturan dengan yang _ = gettext.gettextdigunakan dalam banyak aplikasi yang menggunakan terjemahan)

Varian 2 (nama dummy)

a, unused, unused = foo()

(Tidak terlalu menarik, saya pikir, hal yang sama berlaku untuk nama lain seperti dummy)

Varian 3 (indeks)

a = foo()[0]

(Bagiku ()[0]tampilannya tidak pythonic ...)

pengguna49643
sumber
Berbeda dengan jawaban saya sebelumnya, apa yang terjadi dengan varian 3 ketika Anda sekarang ingin mereferensikan 2/3 dari nilai pengembalian? Saya menghapus jawaban saya karena saya menyadari saya tidak cukup tahu tentang Python untuk membenarkannya.
Craige
@Craige: Saya tidak melihat jawaban Anda sebelum Anda menghapusnya ... Apakah Anda bertanya apakah a, b = foo()[0:2]akan berhasil? Jika ya: ya, ya :)
user49643
Itulah tepatnya yang saya tanyakan. Jika itu berhasil (seperti yang Anda katakan), saya akan menggunakan varian 3. Saya kembali memasukkan jawaban saya yang diberikan informasi ini.
Craige
3
Kebetulan, hari ini Anda dapat menggunakan sintaks yang agak indah untuk 'diperpanjang' membongkar : a, *_ = foo()akan membuang semua nilai kecuali yang pertama.
Benjamin Hodgson
duplikat dari stackoverflow.com/questions/431866/…
Trevor Boyd Smith

Jawaban:

17

Menggunakan garis bawah untuk variabel yang tidak digunakan pasti dapat diterima. Berhati-hatilah, dalam beberapa basis kode itu bukan pilihan karena pengenal itu dicadangkan sebagai singkatan gettext. Ini adalah keberatan paling sering terhadap gaya ini (meskipun ini bukan masalah bagi mayoritas sejauh yang saya bisa menilai). Saya masih merekomendasikannya, dan selalu menggunakannya sendiri.

Nama suka dummyatau unusedcenderung membuat saya jengkel secara pribadi, dan saya tidak sering melihatnya (dengan Python, yaitu - Saya tahu basis kode Delphi yang menggunakan dummysecara bebas, dan ia juga bocor ke skrip yang terkait dengan program yang dimaksud). Saya akan menyarankan Anda menentangnya.

Hanya mengekstraksi satu item dari tuple yang dikembalikan juga tidak masalah. Ini juga menghemat beberapa kerumitan dengan mendapatkan jumlah nilai yang tidak digunakan dengan benar. Perhatikan bahwa ada dua kelemahan potensial:

  • Tidak meledak jika jumlah nilainya berbeda dari yang Anda harapkan. Ini mungkin berguna untuk mendeteksi mixup dan kesalahan ketik.
  • Ini hanya berfungsi ketika nilai kembali adalah urutan (itu sebagian besar tupel dan daftar, tapi mari kita tetap umum). Begitu saja, saya tahu satu kelas dalam kode saya (vektor 2D) yang dapat diubah dan menghasilkan sejumlah nilai konstan (dan dengan demikian dapat digunakan dalam tugas membongkar), tetapi tidak dapat diindeks.

sumber
Saya benar - benar menyebutkan gettext dalam pertanyaan saya :) Pokoknya, saya menerima jawaban Anda - sepertinya tidak ada gaya tunggal yang diterima tetapi jawaban Anda mengangkat beberapa poin menarik.
user49643
Untuk menghindari masalah dengan gettext (atau untuk menghindari masalah yang serupa dalam penerjemah) Anda dapat menggunakan menggarisbawahi dua kali lipat (alias dunders) daripada tunggal.
Zim
21

Pylint membuat saya terbiasa melakukannya dengan cara ini:

widget, _parent, _children = f()

Artinya, hasil yang tidak digunakan memiliki nama deskriptif diawali oleh _. Pylint menganggap penduduk lokal yang diawali dengan _ sebagai tidak terpakai, dan global atau atribut diawali dengan _ sebagai pribadi.

Vincent Povirk
sumber
3

Jika di seluruh proyek Anda, Anda hanya melakukan ini sekali atau sangat jarang menggunakan fungsi tertentu, saya akan menggunakan Varian 1 jika Anda tahu gettextbukan masalah dalam modul itu, dan sebaliknya Varian 3.

Di sisi lain, jika Anda melakukan ini banyak - dan terutama jika setiap kali Anda ingin yang berbeda subset dari nilai kembali (membuat wrapper untuk hanya mengembalikan orang-orang yang Anda sayangi unviable), mungkin akan bermanfaat untuk menulis pembungkus yang menempatkan hasilnya ke dalam tuple bernama , atau turunan dari beberapa kelas deskriptif lain, yang memungkinkan Anda melakukannya:

bar = foo()

Dan kemudian bekerja dengan bar.a, bar.bdan bar.c.

lvc
sumber
2

Seperti yang orang lain katakan, garis bawah ( _) adalah standar. Tetapi jika garis bawah digunakan untuk terjemahan, saya pikir garis bawah ganda adalah alternatif terbaik.

var, __, value = "VAR=value".partition('=')

Lebih baik dari ini:

var, unused, value = "VAR=value".partition('=')

var, unused_del, value = "VAR=value".partition('=')

var, _del, value = "VAR=value".partition('=')

Rick Mohr
sumber
1

Saya seorang programmer non-Python, tetapi bagi saya varian ketiga paling masuk akal.

Dalam varian 3 Anda benar-benar jelas nilai mana yang Anda minati. Dalam varian 1 dan 2, Anda menetapkan nilai kembali ke variabel, dan dengan demikian, mereka dapat digunakan. Anda mungkin menamainya dengan tidak jelas, tetapi penamaan yang buruk sebenarnya bukan solusi untuk masalah apa pun.

Selain kejelasan, mengapa Anda ingin menetapkan nilai yang tidak digunakan ke slot di memori (seperti dalam varian 1 dan 2)? Ini akan menjadi solusi yang buruk dalam hal manajemen memori.

Mendambakan
sumber
Jika Anda selalu meletakkannya di variabel yang sama, bukankah masalah memori hanya akan menjadi ukuran variabel tunggal pada waktu tertentu? Saya tidak berpikir itu harus menjadi masalah.
Michael McQuade
-2

Berikut aturan umum: Jika hanya 1 dari nilai yang dikembalikan digunakan, mengapa tidak mengembalikan saja 1 nilai itu? Jika flag dipanggil dari beberapa tempat, simpan flag untuk nilai yang sama dan kembalikan sesuai dengan flag.

EDIT:

Jika saya berada dalam situasi Anda, dan saya belum menulis fungsinya, saya mungkin akan memilih Variant 2. Saya akan menyimpan nama-nama boneka di sana sehingga parameter dapat digunakan jika perlu. Mengiris daftar akan memiliki sedikit overhead. Mungkin Anda dapat menyisihkan beberapa byte untuk menerima data yang tidak diinginkan.

c0da
sumber
-1 Saya menduga dia tidak mendefinisikan fungsi, dan dengan demikian tidak dapat mengubah apa yang dikembalikan. Saya pikir dia merujuk ketika fungsi mengembalikan 3 nilai, tapi dia hanya peduli 1 dalam kasus penggunaannya saat ini.
Craige
@Craige: Ya, maksud saya fungsi yang tidak bisa saya ubah - saya menambahkan catatan pada pertanyaan saya yang menjelaskan itu.
user49643
Anda yakin dengan biaya overhead? Saya mencoba tes ipython yang sangat sederhana: %timeit a, _, _ = foo()vs %timeit a = foo()[0]yang menghasilkan 123ns vs 109ns, yaitu pengirisan tampaknya sebenarnya lebih cepat daripada nilai membongkar. Atau apakah Anda memiliki situasi tertentu dalam pikiran?
user49643
2
Skenario lain yang masuk akal adalah bahwa Anda tidak memerlukan semua nilai untuk beberapa panggilan.
Keith Thompson