Jak wrócić wielu wartości w Pythonie?

głosy
768

Kanoniczny sposób wrócić wielu wartości w językach, które obsługują to często tupling .

Opcja: Korzystanie krotki

Rozważmy następujący przykład banalny:

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

Jednakże, ten szybko staje się problematyczne, ponieważ liczba wartości zwracane wzrasta. Co zrobić, jeśli chcesz powrócić cztery lub pięć wartości? Oczywiście, można je przechowywać tupling, ale robi się łatwo zapomnieć, których wartość jest gdzie. Jest to także dość brzydki rozpakować je gdziekolwiek chcesz je otrzymywać.

Opcja: Korzystanie ze słownika

Kolejnym logicznym krokiem wydaje się być wprowadzenie pewnego rodzaju „zapis rekordu”. W Pythonie, oczywistym sposobem, aby to zrobić za pomocą środków dict.

Rozważ następujące:

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

(Edit- Wystarczy być jasne, y0, y1 i y2 są tak pomyślane jako abstrakcyjnych identyfikatorów. Jak podkreślił, w praktyce byłoby użyć znaczących identyfikatory)

Teraz mamy mechanizm, dzięki któremu możemy wnioskować z danym państwie zwróconego przedmiotu. Na przykład,

result['y0']

Opcja: Korzystanie z klasy

Jednakże, nie ma innej opcji. Moglibyśmy zamiast wrócić wyspecjalizowaną strukturę. Ja to oprawione w kontekście Python, ale jestem pewien, że ma ona zastosowanie do innych językach. Rzeczywiście, jeśli pracowali w C to może równie dobrze być jedynym rozwiązaniem. Tutaj idzie:

class ReturnValue(object):
  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)

W python poprzednie dwa są prawdopodobnie bardzo podobny pod względem plumbing- Po tym wszystkim { y0, y1, y2 }po prostu skończyć się wpisy w wewnętrznym __dict__z ReturnValue.

Jest jeszcze jedna dodatkowa funkcja dostarczana przez Pythona choć dla małych obiektów, na __slots__atrybut. Klasa może być wyrażona jako:

class ReturnValue(object):
  __slots__ = [y0, y1, y2]
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

Z Python Reference Manual :

__slots__Deklaracja wykonuje sekwencję zmiennych instancji i rezerwy tylko wystarczająco dużo miejsca w każdym przypadku do przechowywania wartości dla każdej zmiennej. Przestrzeń jest zapisane, ponieważ __dict__nie jest tworzony dla każdej instancji.

Opcja: Korzystanie z listy

Kolejna propozycja, która bym wychodził pochodzi z Bill Lizard:

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

Jest to moja najmniej ulubiona metoda choć. Chyba jestem skażony przez ekspozycję na Haskell, ale pomysł list mieszany typu zawsze czuł się nieswojo mnie. W tym konkretnym przykładzie lista jest -not- mieszana, ale niewykluczone, że może być. Lista wykorzystywane w ten sposób naprawdę nie zyskują nic w stosunku do krotki o ile mogę powiedzieć. Jedyną różnicą pomiędzy list i krotek w Pythonie jest to, że listy są zmienne , ubezpieczeniowy krotki nie są. Ja osobiście raczej przeniesienie konwencji z programowania funkcyjnego: Listy użyć dla dowolnej liczby elementów tego samego typu, a krotki dla stałej liczby elementów wyznaczonych typów.

Pytanie

Po długich wstępów przychodzi pytanie nieuniknione. Która metoda (myślisz) jest najlepsza?

Ja znalazłem się zwykle dzieje słownika trasę, ponieważ wymaga mniej pracy set-up. Z perspektywy Rodzaje jednak może być lepiej będzie drogi klasy, ponieważ może pomóc uniknąć mylące co słownikiem reprezentuje. Z drugiej strony, istnieją pewne w społeczności Pythona że czują implikowane interfejsy powinny być preferowane do jawnych interfejsów , w którym momencie typ obiektu naprawdę nie ma znaczenia, ponieważ jesteś w zasadzie opierając się na konwencji, że ten sam atrybut zawsze mają to samo znaczenie.

Tak, jak -you- zwracać wiele wartości w Pythonie?

Utwórz 10/12/2008 o 02:55
źródło użytkownik
W innych językach...                            


14 odpowiedzi

głosy
17

wolę

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

wydaje się, wszystko inne jest po prostu dodatkowy kod do zrobienia tego samego.

Odpowiedział 10/12/2008 o 03:00
źródło użytkownik

głosy
2

W językach takich jak Python, ja zazwyczaj używać słownika, ponieważ wiąże się mniejsze obciążenie niż tworzenie nowej klasy.

Jednakże, jeśli znajdę się stale powraca ten sam zestaw zmiennych, to prawdopodobnie wiąże się z nową klasę, że będę się czynnikiem.

Odpowiedział 10/12/2008 o 03:02
źródło użytkownik

głosy
11

Ogólnie rzecz biorąc, „wyspecjalizowana struktura” faktycznie jest rozsądnym aktualny stan obiektu, z własnymi metodami.

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

Chciałbym znaleźć nazwy struktur anonimowych gdzie to możliwe. Nazwy znaczące uczynić to bardziej jasne.

Odpowiedział 10/12/2008 o 03:15
źródło użytkownik

głosy
156

Dla małych projektów Uważam to najłatwiejszy do pracy z krotek. Kiedy to robi się zbyt trudne do zarządzania (nie wcześniej) zacznę grupowanie rzeczy do struktur logicznych, jednak myślę, że Sposób użycia słowników i obiektów ReturnValue jest źle (lub zbyt uproszczone).

Wracając słownik z kluczami y0, y1, y2 itp nie oferuje żadnej przewagi nad krotek. Zwracanie ReturnValue wystąpienie z właściwości .y0 .y1 .y2 etc nie oferuje żadnej przewagi nad krotek albo. Trzeba zacząć nazywania rzeczy, jeśli chcesz dostać się gdziekolwiek, a można to zrobić za pomocą krotki i tak:

def getImageData(filename):
  [snip]
  return size, (format, version, compression), (width,height)
size, type, dimensions = getImageData(x)

IMHO, jedyną dobrą techniką poza krotek jest powrót realne przedmioty z odpowiednich metod i właściwości, jak można uzyskać z re.match()lub open(file).

Odpowiedział 10/12/2008 o 03:22
źródło użytkownik

głosy
19

Wolę używać krotki gdy krotka czuje się „naturalne”; Współrzędne są typowym przykładem, gdzie oddzielne obiekty mogą stanąć na własnych, na przykład w jednej osi obliczeń tylko skalowanie, a kolejność jest ważna. Uwaga: jeśli można sortować lub przetasować elementów bez niekorzystnego wpływu na sposób, w grupie, to prawdopodobnie nie powinno się używać krotki.

I korzystać ze słowników jako wartość zwracana tylko, gdy zgrupowane obiekty nie zawsze są takie same. Pomyśl opcjonalnych nagłówków e-mail.

Dla pozostałych przypadkach, w których zgrupowane obiekty mają wewnątrz konieczna jest grupa lub pełnoprawnym obiekt z własnymi metodami wrodzoną znaczenie, używam klasy.

Odpowiedział 10/12/2008 o 03:40
źródło użytkownik

głosy
49

Głosuję na słownika.

Uważam, że jeśli zrobię funkcję zwracającą nic więcej niż 2-3 zmiennych będę złożyć je w słowniku. Inaczej zapominają kolejność i treść, co mam wracać.

Ponadto, wprowadzenie „specjalną” struktura sprawia, że ​​Twój kod trudniejsze do naśladowania. (Ktoś inny będzie musiał szukać poprzez kod, aby dowiedzieć się co to jest)

Jeśli chodzi o rodzaj patrzeć, używać opisowych klucze słownika, na przykład, „X-wartości listy”.

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }
Odpowiedział 10/12/2008 o 03:42
źródło użytkownik

głosy
11

+1 na sugestię S.Lott jest o nazwie klasy kontenera.

Dla Pythona 2.6 i do góry, nazwana krotki zapewnia skuteczny sposób na łatwe tworzenie tych klas kontenerowych, a wyniki są „lekkie i nie wymagają więcej pamięci niż zwykłe krotki”.

Odpowiedział 10/12/2008 o 04:51
źródło użytkownik

głosy
481

Nazwane krotki zostały dodane w 2.6 do tego celu. Zobacz także os.stat podobnej wbudowanym przykład.

>>> 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
Odpowiedział 10/12/2008 o 17:36
źródło użytkownik

głosy
11

Krotki Pythona, dicts i obiekty oferują programiście sprawne kompromis między formalności i wygody dla małych struktur danych ( „rzeczy”). Dla mnie wybór sposobu reprezentowania rzeczy podyktowany jest przede wszystkim od tego, jak mam zamiar użyć struktury. W C ++, to wspólna konwencja w użyciu structdla danych tylko do przedmiotów i classobiektów z metod, chociaż można legalnie umieścić metod na zasadzie struct; moim nawykiem jest podobna w Pythonie, z dicti tuplew miejscu struct.

Dla zestawów współrzędnych, będę używać tuplezamiast punktu classlub dict(i pamiętać, że można użyć tuplejako klucz słowniku, więc dicts wspaniałe rozrzedzone tablice wielowymiarowe).

Jeśli mam być iteracji na liście rzeczy, wolę rozpakowywania tupleS na iteracji:

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

... jako wersja przedmiot jest bardziej zaśmiecone czytać:

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

... niech sam dict.

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

Jeśli sprawa jest powszechnie używane, a znajdziesz się robi podobne operacje nietrywialne na nim w wielu miejscach w kodzie, to zwykle warto zrobić to obiekt klasy z odpowiednimi metodami.

Wreszcie, jeśli idę do wymiany danych z elementów systemu non-python, ja najczęściej trzymać je w dictponieważ to najlepiej nadaje się do JSON serializacji.

Odpowiedział 13/08/2013 o 21:18
źródło użytkownik

głosy
26

Innym rozwiązaniem byłoby przy użyciu generatorów:

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

Chociaż IMHO krotki są zwykle najlepsze, z wyjątkiem przypadków, gdy są zwracane wartości są kandydatami do enkapsulacji w klasie.

Odpowiedział 23/02/2014 o 16:26
źródło użytkownik

głosy
20
>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3
Odpowiedział 21/01/2015 o 20:57
źródło użytkownik

głosy
101

Wiele odpowiedzi sugerują, trzeba zwracać kolekcję jakiegoś podobnego do słownika lub listy. Można zostawić poza dodatkową składnię i po prostu wypisać wartości zwracanych, oddzielone przecinkami. Uwaga: to technicznie zwraca krotki.

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

daje:

True
False
Odpowiedział 14/04/2016 o 20:08
źródło użytkownik

głosy
0

Chciałbym użyć dict przejść i wrócić wartości z funkcji:

Korzystać z różnych postaci, jak określono w formie .

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}

Jest to najbardziej efektywny sposób dla mnie i dla jednostki przetwarzającej.

Trzeba zdać tylko jeden wskaźnik i powrócić tylko jeden wskaźnik na zewnątrz.

Nie trzeba zmieniać Funkcje (tysiące z nich) argumentów ilekroć dokonać zmian w kodzie.

Odpowiedział 30/10/2017 o 14:01
źródło użytkownik

głosy
0

„Najlepsza” jest częściowo prywatną decyzją. Używać krotki dla małych zestawów powrotnego w ogólnym przypadku, gdy stały jest dopuszczalne. Krotka jest zawsze korzystne do listy, gdy zmienność nie jest to wymóg.

W przypadku bardziej złożonych wartości zwracanych lub dla przypadku, gdy formalność jest cenna (czyli kodu wysoka wartość) nazwana krotki jest lepsza. Do najbardziej złożonych przypadku obiekt jest zwykle najlepsze. Jednakże, jest to naprawdę sytuacja się liczy. Jeśli ma to sens, aby powrócić do obiektu, ponieważ to, co naturalnie ma na końcu funkcji (np fabryczne wzorzec), a następnie powrócić do obiektu.

Jak mądry człowiek powiedział:

Przedwczesna optymalizacja jest źródłem wszelkiego zła (lub przynajmniej większość z nich) w programowaniu.

Odpowiedział 29/08/2018 o 19:30
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more