Kaip grąžinti kelias funkcijas iš funkcijos?

Kanoninis būdas grąžinti kelias vertes į kalbas, kurios ją palaiko, dažnai yra derinamas .

Parinktis: naudokite paketą

Apsvarstykite šį trivialų pavyzdį:

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

Tačiau tai greitai tampa problematiška, nes padidėja grąžintų verčių skaičius. Ką daryti, jei norite grąžinti keturias ar penkias vertybes? Žinoma, galėtumėte ir toliau jas ištaisyti, bet tai yra lengva pamiršti tiksliai. Taip pat gana negraži juos išpakuoti ten, kur norite.

Parinktis: naudokite žodyną

Kitas logiškas žingsnis, atrodo, yra įvesti tam tikrą „įrašų įrašą“. Pythone akivaizdus būdas tai padaryti yra su dict .

Apsvarstykite šiuos dalykus:

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

(redaguoti) Tiesiog aišku, y0, y1 ir y2 vadinami tik abstrakčiais identifikatoriais. Kaip jau minėta, praktiškai turėtumėte naudoti prasmingus identifikatorius)

Dabar mes turime mechanizmą, kuriuo galime projektuoti konkretų grąžinto objekto narį. Pavyzdžiui

 result['y0'] 

Galimybė: naudoti klasę

Tačiau yra ir kita galimybė. Vietoj to galėtume grąžinti specializuotą struktūrą. Tai sukūriau Python kontekste, bet esu tikras, kad tai taip pat taikoma ir kitoms kalboms. Iš tiesų, jei dirbate su C, tai gali būti jūsų vienintelė galimybė. Čia:

 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) 

Pythone, ankstesni du yra tikriausiai labai panašūs santechnikos atžvilgiu. Galų gale { y0, y1, y2 } tiesiog įveskite įrašus vidinėje __dict__ ReturnValue .

Python teikia vieną papildomą funkciją, nors mažiems objektams atributas yra __slots__ . Klasė gali būti išreikšta kaip:

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

Python“ vadovo vadove :

__slots__ užima tam tikrus egzempliorių kintamųjų sekos ir kiekvienu atveju rezervuoja pakankamai vietos kiekvienam kintamajam. Erdvė išsaugoma, nes __dict__ nėra sukurtas kiekvienam atvejui.

Parinktis: naudoti sąrašą

Kitas praleistas pasiūlymas yra „Bill Lizard“:

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

Tai mano mėgstamiausias metodas. Manau, kad buvau sugadintas susisiekus su Haskelu, bet mišrių sąrašų idėja man atrodė nepatogu. Šiame konkrečiame pavyzdyje sąrašas nėra mišrus, bet gali būti. Kiek aš galiu pasakyti, tokiu būdu naudojamas sąrašas iš tikrųjų negauna nieko, palyginti su paketu. Vienintelis realus skirtumas tarp „Python“ sąrašų ir paketų yra tas, kad sąrašai yra keičiantys, jei jų nėra. Aš asmeniškai linkiu perduoti konvencijas iš funkcinio programavimo: naudoti bet kurio vieno tipo elementų sąrašus ir fiksuotus skaičius iš anksto nustatytų tipų elementų.

Klausimas

Po ilgo preambulės kyla neišvengiamas klausimas. Kuris metodas (ar manote) yra geriausias?

Paprastai aš pastebėjau, kad seku žodyno kelią, nes jis susijęs su mažiau individualaus darbo. Tačiau, kalbant apie tipus, gali būti geriau sekti klasės maršrutą, nes tai gali padėti išvengti painiavos, kas yra žodynas. Kita vertus, „Python“ bendruomenėje yra keletas, kurie numato numanomąsias sąsajas kaip aiškesnes sąsajas , o po to objekto tipas iš tiesų nesvarbu, nes daugiausia remiasi konvencija, kad tas pats atributas visada turi tą pačią vertę.

Taigi, kaip jūs grąžinate kelias vertes į „Python“?

868
10 дек. nustatykite saffsd 10 dec. 2008-12-10 04:55 '08 at 4:55 2008-12-10 04:55
@ 14 atsakymų

Šiam tikslui buvo priskirti pavadinimai 2.6. Taip pat žr .

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

Naujausiose „Python 3“ versijose (3. 6+, manau) naujoji typing biblioteka gavo „ NamedTuple klasę, kad pavadinimai būtų lengviau sukurti ir galingesni. Paveldėjimas iš typing.NamedTuple leidžia naudoti dokumentacijos eilutes, numatytas vertes ir tipo anotacijas.

Pavyzdys (iš dokumentų):

 class Employee(NamedTuple): # inherit from collections.NamedTuple name: str id: int = 3 # default value employee = Employee('Guido') assert employee.id == 3 
552
10 дек. Atsakymas duotas A. Coady gruodžio 10 d. 2008-12-10 19:36 '08 at 7:36 pm 2008-12-10 19:36

Mažesniems projektams man lengviau dirbti su paketais. Kai ji tampa pernelyg sudėtinga valdyti (ir ne anksčiau), pradiu grupuoti daiktus į logines struktūras, tačiau manau, kad siūlomas žodynų ir ReturnValue objektų naudojimas yra neteisingas (arba pernelyg supaprastintas).

Žodyno grąžinimas su klavišais y0, y1, y2 ir tt jokio pranašumo nei „tuples“. Grąžinkite „ReturnValue“ egzempliorių su ypatybėmis .y0.y1.y2 ir tt Taip pat nesuteikia pranašumų prieš eilutes. Jei norite eiti bet kur, turite pradėti skambinti, ir vistiek galite tai padaryti:

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

IMHO, vienintelis geras metodas už re.match() ribų, yra grąžinti realius objektus naudojant tinkamus metodus ir savybes, pavyzdžiui, iš re.match() arba open(file) .

180
10 дек. atsakymas pateikiamas per daug php 10 dec. 2008-12-10 05:22 '08 at 17:22 pm 2008-12-10 05:22

Daugelis atsakymų rodo, kad reikia grąžinti tam tikrą kolekciją, pvz., Žodyną ar sąrašą. Galite palikti papildomą sintaksę ir tiesiog parašyti grąžintas vertes, atskirtas kableliais. Pastaba: tai techniškai grąžina paketą.

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

suteikia:

 True False 
149
14 апр. Joseph Hansen atsakymas, pateiktas balandžio 14 d 2016-04-14 23:08 '16 at 11:08 pm 2016-04-14 23:08

Balsuosiu už žodyną.

Manau, kad jei sukursiu funkciją, kuri grąžina kažką daugiau nei 2-3 kintamuosius, juos paslėpsiu žodynuose. Priešingu atveju bandau pamiršti, ką sugrįžau.

Be to, „specialios“ struktūros įvedimas apsunkina jūsų kodo vykdymą. (Kažkas turės ieškoti kodo, kad sužinotų, kas tai yra)

Jei norite rasti tipą, naudokite aprašomuosius žodynų raktus, pvz., „X reikšmių sąrašą“.

 def g(x): y0 = x + 1 y1 = x * 3 y2 = y0 ** y3 return {'y0':y0, 'y1':y1 ,'y2':y2 } 
62
10 дек. atsakymas, pateiktas „ monkut“, 10 d. 2008-12-10 05:42 '08 at 5:42 2008-12-10 05:42

Kita galimybė būtų naudoti generatorius:

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

Nors IMHO paketai dažniausiai yra geriausi, nebent grąžinamos vertės yra kandidatės į klasę.

33
23 февр. atsakymas pateikiamas rlms vasario 23 d 2014-02-23 18:26 '14 at 18:26 2014-02-23 18:26

Aš norėčiau naudoti paketus, kai jie atrodo „natūralūs“; koordinatės yra tipiškas pavyzdys, kai atskiri objektai gali stovėti savarankiškai, pavyzdžiui, vienašaliuose skaičiavimuose, svarbu tik mastelio nustatymas ir tvarka. Pastaba: jei galiu rūšiuoti ar maišyti elementus nedarant įtakos grupės vertei, tikriausiai neturėčiau naudoti paketo.

Žodynus naudoju kaip grąžinimo vertę tik tada, kai sugrupuoti objektai ne visada yra vienodi. Pagalvokite apie papildomas el. Pašto antraštes.

Kitais atvejais, kai sugrupuoti objektai turi vidinę vertę grupėje arba reikalingas pilnavertis objektas su savo metodais, naudoju klasę.

25
10 дек. atsakymas duotas 10 dec. 2008-12-10 05:40 '08 at 5:40 2008-12-10 05:40
 >>> def func(): ... return [1,2,3] ... >>> a,b,c = func() >>> a 1 >>> b 2 >>> c 3 
22
21 янв. atsakymą pateikė WebQube sausio 21 d 2015-01-21 23:57 '15, 23:57, 2015-01-21 23:57

Aš norėčiau

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

Atrodo, kad visa kita yra tik papildomas kodas, kaip tai padaryti.

22
10 дек. Atsakymą pateikė UnkwnTech 10 gruodis. 2008-12-10 05:00 '08, 5:00, 2008-12-10 05:00

„Tuples“, „dicts“ ir „Python“ objektai suteikia programuotojui sklandų kompromisą tarp formalumų ir patogumo mažoms duomenų struktūroms („dalykams“). Man, kaip pasirinkti, kaip daiktui atstovauti, daugiausia lemia tai, kaip aš naudosiu struktūrą. „C ++“ tai yra įprastas būdas naudoti struct objektams tik duomenims ir class objektams su metodais, net jei galite teisėtai nustatyti metodus struct ; mano įprotis yra panaši į pythoną, o dict ir tuple vietoj struct .

Jei naudojate koordinates, naudoju tuple , o ne class ar dict tašką (ir atkreipkite dėmesį, kad galite naudoti tuple kaip žodyno raktą, taigi, kad daugialypės matricos būtų labai retos).

Jei ketinu rūšiuoti dalykų sąrašą, aš norėčiau išpakuoti tuple iteracijos metu:

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

... nes objekto versija yra daugiau užteršta skaityti:

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

... nekalbant apie dict .

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

Jei šis dalykas plačiai naudojamas, ir jūs pastebėsite, kad atliekate panašias ne trivialias operacijas keliose kodo vietose, tai paprastai verta padaryti jį klasės objektu atitinkamais metodais.

Galiausiai, jei ketinu keistis duomenimis su ne „Python“ sistemos komponentais, dažniausiai juos išsaugosiu dict , nes tai geriausiai tinka JSON serializavimui.

16
13 авг. atsakymą pateikė Russell Borogove 13 rug . 2013-08-13 23:18 '13, 23:18, 2013-08-13 23:18

Paprastai „specializuota struktūra“ iš tikrųjų yra protinga dabartinė objekto būklė su savo metodais.

 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 

Norėčiau rasti anoniminių struktūrų pavadinimus, jei tai įmanoma. Reikšmingi pavadinimai tampa aiškesni.

15
10 дек. Atsakymą S.Lott pateikė gruodžio 10 d. 2008-12-10 05:15 '08 at 5:15 2008-12-10 05:15

+1 - S.Lott siūlymu, pavadinimu konteinerių klasė.

2.6 ir naujesniems „python“ pavadinimams , pavadintas „tuple“, yra naudingas būdas lengvai sukurti šias konteinerių klases, o rezultatai yra lengvi ir nereikalauja daugiau atminties nei įprastos rinkmenos.

14
10 дек. John Fouhy atsakymas, pateiktas gruodžio 10 d. 2008-12-10 06:51 '08 at 6:51 2008-12-10 06:51

Tokiose kalbose kaip „Python“ paprastai naudoju žodyną, nes jis apėmė mažiau pridėtinių nei naujos klasės kūrimas.

Tačiau, jei aš nuolat grąžinu tuos pačius kintamųjų rinkinius, tai tikriausiai yra dėl naujos klasės, kurią apsvarstysiu.

3
10 дек. 10 d. 2008-12-10 05:02 '08 at 5:02 2008-12-10 05:02

Norėčiau perduoti ir grąžinti reikšmes iš funkcijos:

Naudokite formoje apibrėžtą kintamą 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} 

Tai yra efektyviausias būdas man ir perdirbimui.

Jums reikia perduoti tik vieną rodyklę ir grąžinti tik vieną rodyklę.

Jums nereikia keisti funkcijų argumentų (tūkstančių jų), kai darote pakeitimus kode.

3
30 окт. Elio Byberio atsakymas spalio 30 d 2017-10-30 17:01 '17 at 17:01 2017-10-30 17:01

„Geriausias“ yra iš dalies subjektyvus sprendimas. Naudokite mažų grįžimo rinkinių rinkinius bendruoju atveju, kai nepakeičiamas yra priimtinas. Kortelė visuomet yra geriau nei sąrašas, kai nepastovumas yra neprivalomas.

Sudėtingesnėms grąžinimo vertėms arba tuo atveju, kai formalumas yra svarbus (t. Y. Didelės vertės kodas), geriau naudoti pavadintą paketą. Sunkiausiu atveju objektas paprastai yra geriausias. Tačiau tai iš tikrųjų yra situacija. Jei tikslinga grąžinti objektą, nes tai yra tai, ką jūs natūraliai turite funkcijos pabaigoje (pvz., Gamyklos šablonas), tada grąžinkite objektą.

Kaip išminčiai sakė:

Išankstinis optimizavimas yra visų blogio (arba bent jau daugumos) programavimo eigoje.

2
29 авг. atsakymas duotas joel3000 29 rug . 2018-08-29 22:30 '18, 10:30 val. 2018-08-29 22:30

Kiti klausimai apie „ žymių arba Užduoti klausimą