Bagaimana cara mengembalikan beberapa nilai dari sebuah fungsi?

Kanonik cara untuk mengembalikan beberapa nilai dalam bahasa yang mendukung hal ini sering tupling.

Pilihan: Menggunakan sebuah tuple

Pertimbangkan ini contoh sepele:

def f(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return (y0, y1, y2)

Namun, hal ini dengan cepat mendapat bermasalah sebagai jumlah dari nilai-nilai kembali meningkat. Bagaimana jika anda ingin kembali empat atau lima nilai-nilai? Tentu, anda bisa menyimpan tupling mereka, tapi itu akan mudah lupa yang mana. It's juga agak jelek untuk membongkar mereka di mana pun anda ingin menerima mereka.

Pilihan: Menggunakan kamus

Langkah logis berikutnya tampaknya akan memperkenalkan beberapa jenis 'catatan notasi'. Di Python, yang jelas cara untuk melakukan ini adalah dengan cara dict.

Pertimbangkan hal berikut:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0': y0, 'y1': y1 ,'y2': y2}

(Hanya untuk menjadi jelas, y0, y1, dan y2 adalah hanya dimaksudkan sebagai abstrak pengenal. Seperti yang ditunjukkan, dalam prakteknya anda'd gunakan bermakna pengenal.)

Sekarang, kami memiliki mekanisme dimana kita dapat proyek di luar anggota tertentu dari objek kembali. Misalnya,

result['y0']

Pilihan: Menggunakan kelas

Namun, ada pilihan lain. Kita malah bisa kembali struktur khusus. I've ini dibingkai dalam konteks Python, tapi aku'm yakin itu berlaku untuk bahasa lain juga. Memang, jika anda bekerja di C ini mungkin sangat baik menjadi satu-satunya pilihan anda. Here goes:

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)

Di Python sebelumnya dua adalah 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 meskipun untuk benda-benda kecil, yang __slot__ 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 Python Referensi Manual:

__slot__ deklarasi mengambil urutan instance variabel dan cadangan cukup ruang pada masing-masing contoh untuk memegang nilai untuk masing-masing variabel. Ruang diselamatkan karena __dict__ tidak diciptakan untuk masing-masing contoh.

Pilihan: Menggunakan dataclass (Python 3.7+)

Menggunakan Python 3.7's baru dataclasses, kembali satu kelas dengan secara otomatis ditambahkan metode khusus, mengetik dan alat yang berguna lainnya:

@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)

Pilihan: Menggunakan daftar

Saran lain yang saya'a diabaikan berasal dari Tagihan Kadal:

def h(x):
  result = [x + 1]
  result.append(x * 3)
  result.append(y0 ** y3)
  return result

Ini adalah saya yang paling favorit metode sekalipun. Saya kira saya'm tercemar oleh paparan Haskell, tapi ide dicampur-jenis daftar selalu merasa tidak nyaman untuk saya. Dalam contoh khusus ini daftar yang -tidak - jenis campuran, tapi itu bisa dibayangkan.

Daftar yang digunakan dalam cara ini benar-benar doesn't mendapatkan apa-apa sehubungan dengan tuple sejauh yang saya dapat memberitahu. Satu-satunya perbedaan nyata antara list dan tuple dalam Python adalah bahwa daftar berubah, sedangkan tuples yang tidak.

Saya pribadi cenderung untuk membawa lebih dari konvensi dari pemrograman fungsional: gunakan daftar untuk setiap jumlah elemen dari jenis yang sama, dan tupel untuk tetap jumlah unsur-unsur yang telah ditentukan jenis.

Pertanyaan

Setelah panjang basa-basi, datang pertanyaan yang tak terelakkan. Metode yang (menurutmu) adalah yang terbaik?

I've biasanya menemukan diriku pergi kamus rute karena melibatkan lebih sedikit set-up bekerja. Dari jenis perspektif namun, anda mungkin akan lebih baik pergi kelas route, karena yang dapat membantu anda menghindari membingungkan apa kamus mewakili.

Di sisi lain, ada beberapa di Python masyarakat yang merasa tersirat antarmuka harus diutamakan eksplisit interface, di mana titik jenis objek yang benar-benar isn't relevan, karena anda're pada dasarnya bergantung pada konvensi bahwa atribut yang sama akan selalu memiliki arti yang sama.

Jadi, bagaimana -kau - kembali beberapa nilai dalam Python?

Mengomentari pertanyaan (3)

Bernama tupel yang ditambahkan dalam 2.6 untuk tujuan ini. Lihat juga os.stat untuk mirip builtin contoh.

>>> import collections
>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(1, y=2)
>>> p.x, p.y
1 2
>>> p[0], p[1]
1 2

Dalam versi terbaru dari Python 3 (3.6+, saya pikir), baru mengetik perpustakaan mendapat NamedTuple kelas untuk membuat bernama tupel lebih mudah untuk membuat dan lebih kuat. Mewarisi dari mengetik.NamedTuple memungkinkan anda menggunakan docstrings, nilai default, dan jenis penjelasan.

Contoh (Dari dokumen):

class Employee(NamedTuple):  # inherit from collections.NamedTuple
    name: str
    id: int = 3  # default value

employee = Employee('Guido')
assert employee.id == 3
Komentar (10)

Untuk proyek-proyek kecil saya merasa lebih mudah untuk bekerja dengan tupel. Ketika itu terlalu sulit untuk mengelola (bukan sebelum) saya mulai pengelompokan berbagai hal ke dalam struktur logis, namun saya pikir anda disarankan menggunakan kamus dan ReturnValue benda-benda yang salah (atau terlalu sederhana).

Kembali sebuah kamus dengan tombol "y0", "y1", "y2", dll. doesn't menawarkan keuntungan apapun atas tupel. Kembali ReturnValue contoh dengan sifat .y0, .y1, .y2, dll. doesn't menawarkan keuntungan apapun atas tupel baik. Yang anda butuhkan untuk memulai penamaan hal-hal jika anda ingin mendapatkan di mana saja, dan anda dapat melakukan bahwa dengan menggunakan tupel pula:

def get_image_data(filename):
    [snip]
    return size, (format, version, compression), (width,height)

size, type, dimensions = get_image_data(x)

IMHO, satu-satunya teknik yang baik di luar tupel adalah untuk mengembalikan benda-benda nyata dengan tepat metode dan sifat, seperti yang anda dapatkan dari re.pertandingan() atau open(file).

Komentar (3)

Banyak jawaban sarankan anda butuhkan untuk kembali kumpulan dari beberapa macam, seperti kamus atau daftar. Anda bisa meninggalkan ekstra sintaks dan hanya menuliskan kembali nilai-nilai yang dipisahkan koma. Catatan: teknik ini mengembalikan sebuah tupel.

def f():
    return True, False
x, y = f()
print(x)
print(y)

memberikan:

True
False
Komentar (5)

Aku memilih untuk kamus.

Saya menemukan bahwa jika saya membuat sebuah fungsi yang mengembalikan sesuatu yang lebih dari 2-3 variabel I'll lipat mereka di dalam kamus. Jika tidak, saya cenderung lupa urutan dan isi dari apa yang saya'm kembali.

Juga, memperkenalkan 'khusus' struktur membuat kode anda lebih sulit untuk mengikuti. (Orang lain akan memiliki untuk mencari melalui kode untuk mencari tahu apa itu)

Jika anda khawatir tentang jenis tampilan, menggunakan deskriptif kamus tombol, misalnya, 'x-daftar nilai'.

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }
Komentar (4)

Pilihan lain akan menggunakan generator:

>>> def f(x):
        y0 = x + 1
        yield y0
        yield x * 3
        yield y0 ** 4

>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296

Meskipun IMHO tupel biasanya terbaik, kecuali dalam kasus di mana nilai-nilai yang dikembalikan adalah kandidat untuk enkapsulasi dalam kelas.

Komentar (3)

Saya lebih suka menggunakan tuple setiap kali sebuah tuple merasa "alam"; koordinat adalah contoh yang khas, di mana benda-benda yang terpisah dapat berdiri sendiri, misalnya di salah satu sumbu hanya skala perhitungan, dan ketertiban adalah penting. Catatan: jika aku dapat mengurutkan atau mengocok item tanpa efek samping ke makna kelompok, maka saya mungkin seharusnya't menggunakan sebuah tuple.

Saya menggunakan kamus sebagai nilai kembali hanya ketika dikelompokkan benda aren't selalu sama. Berpikir optional header email.

Untuk kasus yang lainnya, yang mana dikelompokkan benda-benda yang memiliki makna yang melekat dalam kelompok atau penuh objek dengan metode sendiri yang dibutuhkan, saya menggunakan sebuah kelas.

Komentar (0)

Yang saya sukai:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

Tampaknya segala sesuatu yang lain hanya tambahan kode untuk melakukan hal yang sama.

Komentar (1)
>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3
Komentar (2)

Umumnya, "berupa struktur" sebenarnya LEBIH masuk akal saat ini keadaan dari sebuah objek, dengan metode sendiri.

class Some3SpaceThing(object):
  def __init__(self,x):
    self.g(x)
  def g(self,x):
    self.y0 = x + 1
    self.y1 = x * 3
    self.y2 = y0 ** y3

r = Some3SpaceThing( x )
r.y0
r.y1
r.y2

Saya ingin mencari nama anonim struktur di mana mungkin. Nama yang bermakna membuat hal-hal yang lebih jelas.

Komentar (0)

Python's tupel, dicts, dan benda-benda yang menawarkan programmer halus tradeoff antara formalitas dan berkualitas untuk usaha kecil data struktur ("sesuatu"). Bagi saya, pilihan cara untuk mewakili hal ini ditentukan terutama oleh bagaimana saya'm akan menggunakan struktur. Dalam C++, it's konvensi umum untuk menggunakan struct untuk data-satunya item dan kelas untuk benda-benda dengan metode, meskipun anda secara hukum dapat menempatkan metode pada struct; kebiasaan saya adalah serupa dalam Python, dengan dict dan tupel di tempat struct.

Untuk mengkoordinasikan set, aku'll menggunakan tupel daripada titik kelas atau dict (dan perhatikan bahwa anda dapat menggunakan tupel sebagai kamus key, jadi `dict ini membuat sparse array multidimensi).

Jika saya'm akan iterasi daftar hal-hal yang saya sukai membongkar `tupel pada iterasi:

for score,id,name in scoreAllTheThings():
    if score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(score,id,name)

...sebagai objek versi lebih berantakan untuk membaca:

for entry in scoreAllTheThings():
    if entry.score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)

...apalagi dict.

for entry in scoreAllTheThings():
    if entry['score'] > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])

Jika hal ini secara luas digunakan, dan anda menemukan diri anda melakukan hal serupa non-sepele operasi di dalam beberapa tempat di dalam kode, maka itu's biasanya bermanfaat untuk membuat sebuah kelas objek dengan metode yang tepat.

Akhirnya, jika saya'm akan bertukar data dengan non-Python komponen sistem, saya'll paling sering menjaga mereka dalam dict karena itu's paling cocok untuk JSON serialisasi.

Komentar (0)

+1 pada S. Lott's saran dari sebuah wadah bernama kelas.

Untuk Python 2.6 dan up, nama tupel menyediakan sebuah cara yang berguna untuk dengan mudah menciptakan wadah kelas, dan hasil yang "ringan dan tidak memerlukan memori lebih banyak daripada biasa tupel".

Komentar (0)

Dalam bahasa seperti Python, biasanya saya akan menggunakan kamus karena melibatkan lebih sedikit overhead daripada menciptakan sebuah kelas baru.

Namun, jika saya menemukan diri saya terus-menerus kembali ke set yang sama dari variabel, maka itu mungkin melibatkan kelas baru yang saya'll faktor luar.

Komentar (0)

Saya akan menggunakan sebuah dict untuk lulus dan kembali nilai-nilai dari sebuah fungsi:

Menggunakan variabel formulir sebagaimana ditetapkan dalam form.

form = {
    'level': 0,
    'points': 0,
    'game': {
        'name': ''
    }
}

def test(form):
    form['game']['name'] = 'My game!'
    form['level'] = 2

    return form

>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}

Ini adalah cara yang paling efisien untuk-ku dan untuk unit pengolahan.

Anda harus lulus salah satu pointer dalam dan kembali hanya satu pointer.

Anda tidak harus mengubah fungsi' (ribuan dari mereka) argumen setiap kali anda membuat perubahan pada kode anda.

Komentar (2)

"Terbaik" adalah sebagian keputusan subjektif. Gunakan tupel untuk kembali kecil set dalam kasus umum di mana abadi adalah dapat diterima. Sebuah tuple adalah selalu lebih baik untuk daftar saat berubah-ubah bukan persyaratan.

Untuk yang lebih kompleks kembali nilai-nilai, atau untuk kasus di mana formalitas berharga (yaitu nilai tinggi kode) yang bernama tupel lebih baik. Untuk kasus yang paling kompleks objek biasanya terbaik. Namun, hal's benar-benar situasi yang penting. Jika itu masuk akal untuk kembali suatu objek karena itu adalah apa yang anda alami di akhir fungsi (misalnya Factory pattern) kemudian kembali objek.

Sebagai orang bijak mengatakan:

Dini optimasi adalah akar dari segala kejahatan (atau setidaknya sebagian besar dari itu) dalam pemrograman.

Komentar (1)