Apakah ada konvensi untuk mengembalikan beberapa item?

10

Dalam Python khusus (saya tidak tahu apakah ini digeneralisasi) apakah ada cara "terbaik" untuk mengembalikan beberapa item dari suatu fungsi?

def func1():
    return a,b #equivalent to (a,b)

def func2():
    return[a,b]

def func3():
    return{"valueA":a,"valueB":b}

Yang pertama adalah apa yang saya lihat paling umum, tetapi saya merasa seperti yang terakhir membuat kode lebih mudah dibaca karena Anda telah menamai output, tetapi saya mungkin kehilangan semacam overhead yang dibuat oleh metode ini?

Devon M.
sumber
Anda tidak mengembalikan banyak argumen; dalam semua contoh ini, Anda mengembalikan satu hasil yang kebetulan merupakan tipe data majemuk (masing-masing tupel, daftar, dan kamus). Jenis data apa yang akan dikembalikan tergantung pada fungsi Anda dan bagaimana itu dimaksudkan untuk digunakan.
Gardenhead
Menarik, saya tidak pernah berpikir seperti itu, jika Anda menjawabnya, saya bisa menerimanya
Devon M

Jawaban:

13

Saya pikir pilihan perlu dipertimbangkan secara ketat dari sudut pandang pemanggil: apa yang paling mungkin perlu dilakukan oleh konsumen?

Dan apa saja fitur menonjol dari setiap koleksi?

  • Tuple diakses dalam urutan dan tidak berubah
  • Daftar ini diakses secara berurutan dan dapat diubah
  • Dict diakses dengan kunci

Daftar dan tuple setara untuk akses, tetapi daftar bisa berubah. Nah, itu tidak masalah bagi saya penelepon jika saya akan segera membongkar hasilnya:

score, top_player = play_round(players)
# or
idx, record = find_longest(records)

Tidak ada alasan di sini bagi saya untuk peduli apakah itu daftar atau tupel, dan tupel lebih sederhana di kedua sisi.

Di sisi lain, jika koleksi yang dikembalikan akan disimpan utuh dan digunakan sebagai koleksi :

points = calculate_vertices(shape)
points.append(another_point)
# Make a new shape

maka mungkin masuk akal jika kembalinya bisa berubah. Homogenitas juga merupakan faktor penting di sini. Katakanlah Anda telah menulis fungsi untuk mencari urutan untuk pola yang berulang. Informasi yang saya dapatkan kembali adalah indeks dalam urutan instance pertama dari pola, jumlah pengulangan, dan pola itu sendiri. Itu bukan hal yang sama. Meskipun saya mungkin menyimpan potongan-potongan itu, tidak ada alasan saya ingin mengubah koleksi . Ini bukan list.

Sekarang untuk kamus.

yang terakhir membuat kode lebih mudah dibaca karena Anda telah menamai keluaran

Ya, memiliki kunci untuk bidang membuat data heterogen lebih eksplisit, tetapi juga dilengkapi dengan beberapa pembebanan. Sekali lagi, untuk kasus "Saya hanya akan membongkar barang", ini

round_results = play_round(players)
score, top_player = round_results["score"], round_results["top_player"]

(bahkan jika Anda menghindari string literal untuk kunci), adalah pekerjaan yang tidak perlu dibandingkan dengan versi tuple.

Pertanyaannya ada tiga: seberapa rumit koleksinya, berapa lama koleksinya akan disatukan, dan apakah kita perlu menggunakan koleksi yang sama di banyak tempat yang berbeda?

Saya menyarankan bahwa nilai balik akses-kunci mulai lebih masuk akal daripada tuple ketika ada lebih dari sekitar tiga anggota, dan terutama di mana ada sarang:

shape["transform"]["raw_matrix"][0, 1] 
# vs.
shape[2][4][0, 1]

Itu mengarah ke pertanyaan berikutnya: apakah koleksi akan meninggalkan ruang lingkup ini utuh, di suatu tempat jauh dari panggilan yang membuatnya? Akses kunci di sana benar-benar akan membantu pemahaman.

Pertanyaan ketiga - penggunaan kembali - menunjuk ke tipe data kustom sederhana sebagai opsi keempat yang tidak Anda presentasikan.

Apakah struktur semata-mata dimiliki oleh fungsi yang satu ini? Atau apakah Anda membuat tata letak kamus yang sama di banyak tempat? Apakah banyak bagian lain dari program perlu beroperasi pada struktur ini? Tata letak kamus yang berulang harus difaktorkan ke kelas. Bonus di sana adalah Anda dapat melampirkan perilaku: mungkin beberapa fungsi yang beroperasi pada data dienkapsulasi sebagai metode.

Opsi kelima bagus, ringan, adalah namedtuple(). Ini pada dasarnya adalah bentuk yang tidak berubah dari nilai pengembalian kamus.

jscs
sumber
Apakah ada alasan Anda tidak menyebutkan contoh kelas yang ditentukan pengguna sama sekali? Itu harus menjadi solusi goto dalam bahasa OO apa pun.
Esben Skov Pedersen
1
Itu tercakup dalam paragraf ketiga hingga terakhir dan kedua hingga terakhir, @EsbenSkovPedersen. "Tata letak kamus yang berulang harus difaktorkan ke kelas."
jscs
1

Jangan pikirkan fungsi yang mengembalikan banyak argumen. Secara konseptual, yang terbaik adalah memikirkan fungsi sebagai menerima dan mengembalikan satu argumen. Fungsi yang tampaknya menerima banyak argumen sebenarnya hanya menerima satu argumen tipe tuple ( produk resmi ). Demikian pula, fungsi yang mengembalikan banyak argumen hanya mengembalikan tuple.

Dengan Python:

def func(a, b, c):
  return b, c

dapat ditulis ulang sebagai

def func(my_triple):
  return (my_triple[1], my_triple[2])

untuk membuat perbandingan jelas.

Kasus pertama hanyalah gula sintaksis untuk yang terakhir; keduanya menerima triple sebagai argumen, tetapi pola pertama cocok dengan argumennya untuk melakukan perusakan otomatis ke dalam komponen-komponen penyusunnya. Dengan demikian, bahkan bahasa tanpa pencocokan pola umum penuh mengakui beberapa bentuk pencocokan pola dasar pada beberapa jenisnya (Python mengakui pencocokan pola pada kedua produk dan jenis rekaman).


Untuk kembali ke pertanyaan yang ada: tidak ada jawaban tunggal untuk pertanyaan Anda, karena itu seperti bertanya "apa yang harus menjadi tipe pengembalian dari fungsi arbitrer"? Itu tergantung pada fungsi dan use case. Dan, kebetulan, jika "nilai pengembalian berganda" benar-benar independen, maka mereka mungkin harus dihitung dengan fungsi yang terpisah.

kepala kebun
sumber