Cara kanonik untuk mengembalikan beberapa nilai dalam bahasa yang mendukungnya seringkali tupling .
Opsi: Menggunakan tuple
Pertimbangkan contoh sepele ini:
def f(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return (y0, y1, y2)
Namun, ini dengan cepat menjadi bermasalah karena jumlah nilai yang dikembalikan meningkat. Bagaimana jika Anda ingin mengembalikan empat atau lima nilai? Tentu, Anda bisa terus menggelitiknya, tetapi mudah melupakan nilai mana. Ini juga agak jelek untuk membongkar mereka di mana pun Anda ingin menerimanya.
Opsi: Menggunakan kamus
Langkah logis berikutnya tampaknya adalah memperkenalkan semacam 'catatan notasi'. Dalam Python, cara yang jelas untuk melakukan ini adalah dengan cara a dict
.
Pertimbangkan yang berikut ini:
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0': y0, 'y1': y1 ,'y2': y2}
(Untuk lebih jelasnya, y0, y1, dan y2 hanya dimaksudkan sebagai pengidentifikasi abstrak. Seperti yang ditunjukkan, dalam praktiknya Anda akan menggunakan pengidentifikasi yang bermakna.)
Sekarang, kami memiliki mekanisme di mana kami dapat memproyeksikan anggota tertentu dari objek yang dikembalikan. Sebagai contoh,
result['y0']
Opsi: Menggunakan kelas
Namun, ada opsi lain. Kami malah bisa mengembalikan struktur khusus. Saya telah membingkai ini dalam konteks Python, tapi saya yakin itu berlaku untuk bahasa lain juga. Memang, jika Anda bekerja di C ini mungkin satu-satunya pilihan Anda. Ini dia:
class ReturnValue:
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return ReturnValue(y0, y1, y2)
Dalam Python dua sebelumnya mungkin sangat mirip dalam hal pipa - setelah semua { y0, y1, y2 }
hanya berakhir menjadi entri dalam internal __dict__
dari ReturnValue
.
Ada satu fitur tambahan yang disediakan oleh Python untuk objek kecil, yaitu __slots__
atribut. Kelas dapat dinyatakan sebagai:
class ReturnValue(object):
__slots__ = ["y0", "y1", "y2"]
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
Dari Manual Referensi Python :
The
__slots__
deklarasi mengambil urutan variabel instance dan cadangan cukup ruang di setiap contoh untuk mengadakan nilai untuk setiap variabel. Spasi disimpan karena__dict__
tidak dibuat untuk setiap instance.
Opsi: Menggunakan dataclass (Python 3.7+)
Menggunakan kacamata baru Python 3.7, kembalikan kelas dengan metode khusus yang ditambahkan secara otomatis, pengetikan dan alat lain yang bermanfaat:
@dataclass
class Returnvalue:
y0: int
y1: float
y3: int
def total_cost(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return ReturnValue(y0, y1, y2)
Opsi: Menggunakan daftar
Saran lain yang saya abaikan berasal dari Bill the Lizard:
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
Ini adalah metode yang paling tidak kusukai. Saya kira saya dinodai oleh paparan Haskell, tetapi gagasan daftar tipe campuran selalu terasa tidak nyaman bagi saya. Dalam contoh khusus ini daftarnya adalah -tidak- jenis campuran, tetapi bisa dibayangkan bisa.
Daftar yang digunakan dengan cara ini benar-benar tidak mendapatkan apa pun sehubungan dengan tuple sejauh yang saya tahu. Satu-satunya perbedaan nyata antara daftar dan tupel dalam Python adalah bahwa daftar dapat diubah , sedangkan tupel tidak.
Saya pribadi cenderung membawa konvensi dari pemrograman fungsional: gunakan daftar untuk sejumlah elemen dari jenis yang sama, dan tuple untuk sejumlah elemen tetap dari tipe yang telah ditentukan.
Pertanyaan
Setelah pembukaan panjang, muncul pertanyaan yang tak terhindarkan. Metode mana (menurut Anda) yang terbaik?
sumber
y3
, tetapi kecuali y3 dinyatakan global, ini akan menghasilkanNameError: global name 'y3' is not defined
mungkin hanya menggunakan3
?y3
, yang akan melakukan pekerjaan yang sama juga.Jawaban:
Tuple tuple ditambahkan dalam 2.6 untuk tujuan ini. Juga lihat os.stat untuk contoh bawaan serupa.
Dalam versi terbaru Python 3 (3,6+, saya pikir),
typing
perpustakaan baru membuatNamedTuple
kelas untuk membuat tuple bernama lebih mudah untuk dibuat dan lebih kuat. Mewarisi darityping.NamedTuple
memungkinkan Anda menggunakan dokumen, nilai default, dan ketik anotasi.Contoh (Dari dokumen):
sumber
namedtuple
adalah memiliki jejak memori yang lebih kecil untuk hasil massal (daftar panjang tupel, seperti hasil permintaan DB). Untuk setiap item (jika fungsi yang dimaksud tidak sering dipanggil) kamus dan kelas juga baik-baik saja. Tapi namedtuples adalah solusi yang bagus / lebih bagus dalam hal ini juga.namedtuple
definisi (setiap panggilan membuat yang baru), membuatnamedtuple
kelas relatif mahal baik dalam CPU dan memori, dan semua definisi kelas secara intrinsik melibatkan referensi siklik (jadi pada CPython, Anda sedang menunggu siklus siklik GC bagi mereka untuk dirilis). Itu juga membuat tidak mungkin untukpickle
kelas (dan karena itu, tidak mungkin untuk menggunakan contoh denganmultiprocessing
dalam kebanyakan kasus). Setiap pembuatan kelas pada 3,6,4 x64 saya mengkonsumsi ~ 0,337 ms, dan menempati hanya di bawah 1 KB memori, membunuh tabungan contoh apa pun.namedtuple
kelas baru ; biaya CPU turun kira-kira faktor 4x , tetapi mereka masih kira-kira 1000x lebih tinggi daripada biaya untuk membuat instance, dan biaya memori untuk setiap kelas tetap tinggi (saya salah dalam komentar terakhir saya tentang "di bawah 1 KB" untuk kelas,_source
dengan sendirinya biasanya 1,5 KB;_source
dihapus dalam 3,7, sehingga kemungkinan lebih dekat dengan klaim asli di bawah 1 KB per pembuatan kelas).Untuk proyek kecil saya merasa paling mudah untuk bekerja dengan tuple. Ketika itu menjadi terlalu sulit untuk dikelola (dan bukan sebelumnya) saya mulai mengelompokkan hal-hal ke dalam struktur logis, namun saya pikir Anda menyarankan penggunaan kamus dan
ReturnValue
objek adalah salah (atau terlalu sederhana).Kembali kamus dengan tombol
"y0"
,"y1"
,"y2"
, dll tidak menawarkan keuntungan apapun atas tupel. MengembalikanReturnValue
contoh dengan sifat.y0
,.y1
,.y2
, dll tidak menawarkan keuntungan apapun atas tupel baik. Anda harus mulai memberi nama hal-hal jika Anda ingin pergi ke mana saja, dan Anda bisa melakukannya menggunakan tuple:IMHO, satu-satunya teknik yang baik di luar tuple adalah mengembalikan objek nyata dengan metode dan properti yang tepat, seperti yang Anda dapatkan dari
re.match()
atauopen(file)
.sumber
size, type, dimensions = getImageData(x)
dan(size, type, dimensions) = getImageData(x)
? Yaitu, apakah membungkus sisi kiri dari tugas tupled ada bedanya?(1)
adalah int sementara(1,)
atau1,
tupel.Banyak jawaban menyarankan Anda perlu mengembalikan koleksi, seperti kamus atau daftar. Anda dapat mengabaikan sintaks tambahan dan cukup menuliskan nilai-nilai pengembalian, dipisahkan dengan koma. Catatan: ini secara teknis mengembalikan tupel.
memberi:
sumber
type(f())
kembali<class 'tuple'>
.tuple
aspek eksplisit; itu tidak benar-benar penting bahwa Anda mengembalikan atuple
, ini adalah ungkapan untuk mengembalikan periode beberapa nilai. Alasan yang sama Anda menghilangkan parens dengan idiom swapx, y = y, x
,, inisialisasi bergandax, y = 0, 1
, dll .; tentu, itu membuattuple
s di bawah tenda, tetapi tidak ada alasan untuk membuat itu eksplisit, karenatuple
s bukan intinya sama sekali. Tutorial Python memperkenalkan banyak penugasan jauh sebelum bahkan menyentuh padatuple
s.=
adalah tuple dengan Python dengan atau tanpa tanda kurung di sekitarnya. Jadi sebenarnya tidak ada eksplisit atau implisit di sini. a, b, c sebanyak tupel (a, b, c). Juga tidak ada pembuatan tuple "di bawah tenda" ketika Anda mengembalikan nilai seperti itu, karena itu hanya tuple sederhana. OP sudah menyebutkan tupel sehingga sebenarnya tidak ada perbedaan antara apa yang ia sebutkan dan apa yang ditunjukkan jawaban ini. Tidak adaSaya memilih kamus.
Saya menemukan bahwa jika saya membuat fungsi yang mengembalikan lebih dari 2-3 variabel, saya akan melipatnya dalam kamus. Kalau tidak, saya cenderung lupa urutan dan isi dari apa yang saya kembalikan.
Juga, memperkenalkan struktur 'khusus' membuat kode Anda lebih sulit untuk diikuti. (Orang lain harus mencari melalui kode untuk mencari tahu apa itu)
Jika Anda khawatir tentang mengetikkan pencarian, gunakan kunci kamus deskriptif, misalnya, 'daftar nilai x'.
sumber
result = g(x); other_function(result)
Opsi lain akan menggunakan generator:
Meskipun tuple IMHO biasanya yang terbaik, kecuali dalam kasus di mana nilai yang dikembalikan adalah kandidat untuk enkapsulasi di kelas.
sumber
yield
?def f(x): …; yield b; yield a; yield r
vs(g for g in [b, a, r])
, dan keduanya akan mudah dikonversi ke daftar atau tuple, dan dengan demikian akan mendukung tuple membongkar. Bentuk generator tuple mengikuti pendekatan fungsional, sedangkan bentuk fungsi sangat penting dan akan memungkinkan kontrol aliran dan penugasan variabel.Saya lebih suka menggunakan tuple setiap kali tuple terasa "alami"; koordinat adalah contoh khas, di mana objek yang terpisah dapat berdiri sendiri, misalnya dalam perhitungan penskalaan hanya satu sumbu, dan urutannya penting. Catatan: jika saya bisa mengurutkan atau mengacak item tanpa efek buruk pada arti dari grup, maka saya mungkin tidak boleh menggunakan tuple.
Saya menggunakan kamus sebagai nilai kembali hanya ketika objek yang dikelompokkan tidak selalu sama. Pikirkan tajuk email opsional.
Untuk sisa kasus, di mana objek yang dikelompokkan memiliki makna yang melekat di dalam grup atau objek yang lengkap dengan metode sendiri diperlukan, saya menggunakan kelas.
sumber
Saya lebih memilih:
Sepertinya yang lainnya hanyalah kode tambahan untuk melakukan hal yang sama.
sumber
sumber
Secara umum, "struktur khusus" sebenarnya adalah keadaan saat objek yang masuk akal, dengan metode sendiri.
Saya suka mencari nama untuk struktur anonim jika memungkinkan. Nama yang bermakna membuat segalanya lebih jelas.
sumber
Tuple, dikts, dan objek Python menawarkan program pertukaran yang mulus antara formalitas dan kenyamanan untuk struktur data kecil ("barang"). Bagi saya, pilihan bagaimana mewakili sesuatu ditentukan terutama oleh bagaimana saya akan menggunakan struktur. Di C ++, ini adalah konvensi yang umum digunakan
struct
untuk item data saja danclass
untuk objek dengan metode, meskipun Anda dapat menggunakan metode secara legalstruct
; kebiasaan saya mirip dengan Python, dengandict
dantuple
di tempatstruct
.Untuk set koordinat, saya akan menggunakan
tuple
daripada titikclass
ataudict
(dan perhatikan bahwa Anda dapat menggunakantuple
sebagai kunci kamus, jadidict
buatlah array multidimensi yang jarang).Jika saya akan mengulangi daftar hal-hal, saya lebih suka membongkar
tuple
pada iterasi:... karena versi objek lebih berantakan untuk dibaca:
... apalagi itu
dict
.Jika hal itu banyak digunakan, dan Anda menemukan diri Anda melakukan operasi non-sepele yang serupa di beberapa tempat dalam kode, maka biasanya bermanfaat untuk menjadikannya objek kelas dengan metode yang tepat.
Akhirnya, jika saya akan bertukar data dengan komponen sistem non-Python, saya paling sering menyimpannya di
dict
karena itu paling cocok untuk serialisasi JSON.sumber
Beri +1 pada saran S.Lott tentang kelas wadah bernama.
Untuk Python 2.6 dan yang lebih tinggi, tuple yang diberi nama menyediakan cara yang berguna untuk dengan mudah membuat kelas kontainer ini, dan hasilnya "ringan dan tidak memerlukan lebih banyak memori daripada tupel biasa".
sumber
Dalam bahasa seperti Python, saya biasanya menggunakan kamus karena melibatkan lebih sedikit overhead daripada membuat kelas baru.
Namun, jika saya menemukan diri saya terus-menerus mengembalikan set variabel yang sama, maka itu mungkin melibatkan kelas baru yang saya akan faktor keluar.
sumber
Saya akan menggunakan dict untuk meneruskan dan mengembalikan nilai dari suatu fungsi:
Gunakan formulir variabel seperti yang didefinisikan dalam formulir .
Ini adalah cara paling efisien untuk saya dan untuk unit pemrosesan.
Anda harus melewati hanya satu pointer dan mengembalikan hanya satu pointer.
Anda tidak perlu mengubah argumen fungsi (ribuan dari mereka) setiap kali Anda membuat perubahan dalam kode Anda.
sumber
test
akan langsung mengubah nilainya. Bandingkan dengan inidict.update
, yang tidak mengembalikan nilai.form
tidak merusak keterbacaan atau kinerja. Dalam kasus di mana Anda mungkin perlu memformat ulangform
, mengembalikannya [formulir] memastikan bahwa yang terakhirform
dikembalikan karena Anda tidak akan melacak perubahan formulir di mana pun."Terbaik" adalah keputusan yang sebagian subjektif. Gunakan tuple untuk set return kecil dalam kasus umum di mana immutable dapat diterima. Sebuah tuple selalu lebih disukai daripada daftar ketika mutabilitas bukan keharusan.
Untuk nilai pengembalian yang lebih kompleks, atau untuk kasus di mana formalitas bernilai (yaitu kode nilai tinggi), tuple bernama lebih baik. Untuk kasus yang paling kompleks, objek biasanya adalah yang terbaik. Namun, sebenarnya situasi itulah yang penting. Jika masuk akal untuk mengembalikan objek karena itulah yang secara alami Anda miliki di akhir fungsi (misalnya pola Pabrik), maka kembalikan objek tersebut.
Seperti kata orang bijak:
sumber