Mulla on ongelma ohjelmien suunnittelussa. Tuntuu siltä, että aina kun teen vähänkään monimutkaista ohjelmaa, teen funktioista liian isoja ja ne tarvitsevat kamalan monta parametria. Miten kannattaisi opetella tekemään vähäparametrisia funktioita? Ainakin yksi tapa olisi pistää kaikki argumentit listaan ja funktio ottaisi parametrina tuon lista-argumentin. En usko, että tällainen olisi kovin tyylikästä.
Vaikea sanoa tuntematta funktioitasi, mutta tässä pari ehdotusta:
Jos parametrit liittyvät toisiinsa, kannattaa harkita niiden laittamista luokkaan. Tätä luokkaa kannattaa sitten käyttää muissakin funktioissa. Parhaimmillaan pääset samalla eroon koko joukosta muuttujia.
Alla lyhyt esimerkki.
# ennen def tulostaTiedot(nimi, ikä, sukupuoli): print("Nimi:", nimi) print("Ikä:", ikä) print("Sukupuoli:", sukupuoli) # jälkeen class Henkilö: def __init__(self, nimi, ikä, sukupuoli): self.nimi = nimi self.ikä = ikä self.sukupuoli = sukupuoli def tulostaTiedot(henkilö): print("Nimi:", henkilö.nimi) print("Ikä:", henkilö.ikä) print("Sukupuoli:", henkilö.sukupuoli)
Listaan parametrit kannattaa laittaa vain, jos ne oikeasti kuvaavat listaa (jonka koko voi vaihdella).
Kannattaa myös harkita funktioiden muuttamista metodeiksi. Esimerkissä tulostaTiedot
voisi hyvin olla Henkilö
-luokan metodi.
Suuri määrä parametreja voi merkitä sitä, että funktiosi tekee liian monta asiaa. Ideaalisti yksi funktio tekee vain yhden asian.
Jos funktion voi helposti jakaa kahteen tai useampaan osaan, joista jokainen käyttää vain osaa argumenteista, kannattaa tehdä niin.
Jos funktiolle annetaan aina samat argumentit ohjelman suorituksen aikana, tai siis jos argumentit ovat vakioita, voisiko nämä laittaa globaaleihin muuttujiin?
# ennen def tulostaLokiin(tiedosto, aika, viesti): # ... # jälkeen lokitiedosto = "log.txt" def tulostaLokiin(viesti): tiedosto = lokitiedosto aika = datetime.datetime.now() # ...
Tyylikkäintä olisi tehdä tästäkin luokka Lokitiedosto
, joka sisältää tiedoston nimen ja metodin tulostaLokiin
. Silloin parametreja olisi yhtä vähän, mutta lokitiedostoja voisi silti tarvittaessa olla useampia.
Yritin ratkoa putkapostia Ahdas ruudukko. Koodista tuli vaan ylimonimutkainen bugikasa.
Vaikka luokkien käyttäminen on tavallaan yksi ratkaisu ongelmaan, niin se on aika usein kuitenkin aloittelijatason kysymyksissä huono ratkaisu, koska bloatti ja sekava luokka on aivan yhtä huono asia kuin liian monta parametria vaativa funktio.
Funktion tarkoitus on ratkaista ongelma. Iso ongelma tulee jakaa pienempiin osaongelmiin, jotka voi ratkaista itsenäisinä asioina tietyllä määrällä parametreja. Ratkaisut voi sen jälkeen ketjuttaa antamalla seuraavalle funktiolle edellisen tuottaman arvon yhtenä parametrina.
Aloittelija tekee usein myös sen virheen, että lähtee optimoimaan ratkaisua jo ennen kuin kyseistä ratkaisua on olemassa. Tällöin parametreihin saattaa tulla kaikenlaisia ylimääräisiä asioita, jotka olevinaan nopeuttavat laskentaa mutta samalla tekevät kaikesta niin hemmetin monimutkaista. Jos tästä on kyse, niin yritäpä ensin tehdä yksinkertaisin mahdollinen (ts. usein brute forceen perustuva) algoritmi ja mieti myöhemmin sen nopeuttamista, mikäli sille on edes tarvetta.
Kokelin testiksi ratkaista tuota Putkapostia tekemällä joukon yksinkertaisia funktioita ns. lennosta. Sain toimivan ratkaisun yhdeksällä funktiolla, joista jokainen ottaa enintään neljä parametria. Käytännössä loin aina uuden funktion, kun sisäkkäisiä silmukoita olisi tullut liikaa. (Ratkaisuni ei jostain syystä ole optimaalinen, koska löytää pienimmillään 3x8 ruudukon.)
P.S. Globaalit on syöpä, älä käytä niitä.
The Alchemist kirjoitti:
P.S. Globaalit on syöpä, älä käytä niitä.
Globaalit ovat erinomainen ratkaisu tietyissä tilanteissa. Jos käytetyt arvot ovat vakioita koko ohjelman suorituksen ajan, ei ole mitään järkeä kuljettaa niitä parametreissa. Vaikka jokin käytetty algoritmi voisikin teoriassa käyttää muitakin vakion arvoja, on usein yksinkertaisten ohjelmien kannalta täysin turhaa tarjota niille tukea varsinkin, jos ohjelmaan sopivat vain tietyt vakion arvot.
Valmiiksi tunnetuille vakioille Python tarjoaakin jo oman ratkaisunsa: parametrien oletusarvot, mutta esimerkiksi tiedostosta ladattavat arvot voi laittaa globaaleihin muuttujiin. Lisäksi yllä antamassani esimerkissä lokitiedoston polku kannattaa pitää omassa muuttujassaan vaikkapa kooditiedoston alussa, jotta se on helppo löytää ja muuttaa tarvittaessa.
Aihe on jo aika vanha, joten et voi enää vastata siihen.