Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Saako Python-funktio parametrin?

Jaska [09.11.2013 00:25:34]

#

Mikä on oikeaoppinen tapa tarkistaa, saako funktio parametrin? Harjoitustehtävänä on tehdä henkilötietojen haku- ja tulostusohjelma, ja ajattelin harjoitella funktioiden käyttöä. Mutta teenkö asian alla olevassa koodissa oikeaoppisesti vai en?

# -*- coding: utf-8 -*-

def nimi():
  nimimuuttuja = str(input("Anna nimi: "))
  return nimimuuttuja

def tulosta(nimi):
  tuloste=""
  if str(type(nimi)) != "<class 'function'>":
    nimi=str(nimi)
    tuloste+="Nimi: "+nimi
  print(tuloste)

komento=""
while komento!="q":
  komento=str(input("Anna komento:"))
  if komento=="n":
    nimi=nimi()
  if komento=="t":
    tulosta(nimi)

Metabolix [09.11.2013 00:45:11]

#

Koodissasi ei ole kyse siitä, saako funktio parametrin, vaan siitä, saako funktio parametriksi alussa määritellyn funktion vai myöhemmin syötetyn tekstin.

Mistä noin järjettömiä keksintöjä syntyy? On ihan älytöntä ensin määritellä funktio ja sitten luoda samanniminen tekstimuuttuja, ja vielä hullumpaa on joutua tarkistamaan tuota outoa tilannetta. Käytännön vika ohjelmassasi on, että jos syöttää n-komennon kahdesti, ohjelma kaatuu.

Järkevää olisi käyttää ensimmäiselle funktiolle eri nimeä ja alustaa muuttuja tyhjäksi. Silloin toisessa funktiossa voisi tarkistaa, onko parametri tyhjä, ja tilanne olisi paljon selvempi.

Ohjelma voisi toimia järkevästi vaikkapa näin:

def lue():
  return input("Anna nimi: ")

def tulosta(nimi):
  if nimi is None:
    print("Nimeä ei ole syötetty.")
  else:
    print("Nimi: " + nimi)

nimi = None
while True:
  komento = input("Anna komento: ")
  if komento == "q":
    break
  elif komento == "n":
    nimi = lue()
  elif komento == "t":
    tulosta(nimi)
  else:
    print("Tuntematon komento!")

Chiman [09.11.2013 14:58:29]

#

Jaska kirjoitti:

Mikä on oikeaoppinen tapa tarkistaa, saako funktio parametrin?

Kun ohjelman suoritus menee funktion sisään, on sinne aina annettu parametri, jos funktion määrittely on tällainen:

def tulosta(nimi):

Tuo tarkoittaa, että funktio saa aina tasan yhden parametrin. Jos sitä yrittää kutsua eri määrällä, kutsun yhteydessä lentää poikkeus. Näitä voi testata helposti Python-komentokehotteessa tähän tapaan:

>>> def tulosta(nimi):
...     pass
...
>>> tulosta()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: tulosta() takes exactly 1 argument (0 given)
>>>

Kun suoritus on edennyt tulosta-funktion sisään, nimi-muuttuja viittaa funktion sisällä aina sen saamaan parametriin eli funktion sisältä et voi helposti edes nähdä nimi-nimistä funktiota. Toki sekin onnistuu esim. globals-funktion käytöllä.

Tässä erilaisia keinoja määritellä funktiolle annettavia parametrejä. Näitä keinoja voi myös yhdistellä tiettyjen sääntöjen mukaan:

def tulosta(nimi):  # yksi parametri
def tulosta(nimi=None):  # yksi vapaaehtoinen parametri, oletuksena None
def tulosta(*nimet):  # 0 tai useampi parametri, tulevat nimet-nimiseen tupleen
def tulosta(**nimet):  # 0 tai useampi nimetty parametri, tulevat nimet-nimiseen sanakirjaan

Esimerkki funktiosta ja sen kutsumisesta:

>>> def tulosta(sukunimi, etunimi=None, *osoitetiedot, **muut_tiedot):
...     print sukunimi, etunimi, osoitetiedot, muut_tiedot
...
>>> tulosta('Virtanen')
Virtanen None () {}
>>> tulosta('Virtanen', 'Matti')
Virtanen Matti () {}
>>> tulosta('Virtanen', 'Matti', 'Putkatie 1', '12345 Koodila')
Virtanen Matti ('Putkatie 1', '12345 Koodila') {}
>>> tulosta('Virtanen', 'Matti', 'Putkatie 1', '12345 Koodila', ovikoodi='01234')
Virtanen Matti ('Putkatie 1', '12345 Koodila') {'ovikoodi': '01234'}
>>> tulosta('Virtanen', ovikoodi='01234')
Virtanen None () {'ovikoodi': '01234'}

Jaska [09.11.2013 18:08:39]

#

Kiitos kummallekin! Sain nyt tehtyä tuon omasta mielestäni fiksummin, enkä huomannut enää kaatumisia.

# coding: utf-8

def lue_nimi():
  return input("Anna nimi: ")

def lue_ika():
  kunnossa=False
  while not kunnossa:
    ika=input("Anna ikä: ")
    try:
      ika=int(ika)
      if ika>=0:
        kunnossa=True
    except ValueError:
      kunnossa=False
  return ika

def lue_paikka():
  return input("Anna asuinpaikka: ")

def tulosta(nimi, ika, paikka):
  tuloste=""
  if nimi is not None:
    tuloste+="Nimi: "+nimi
  if ika is not None:
    if tuloste!="":
      tuloste+="\n"
    tuloste+="Ikä: "+str(ika)
  if paikka is not None:
    if tuloste!="":
      tuloste+="\n"
    tuloste+="Asuinpaikka: "+paikka
  print(tuloste)

def ohje():
  print("Ohje: n - syötä nimi, i - syötä ikä, a - syötä asuinpaikka, t - tulosta, o - ohje, q - lopeta")

nimi=None
ika=None
paikka=None
komento=""

while komento!="q":
  komento=input("Anna komento: ")
  if komento=="n":
    nimi=lue_nimi()
  if komento=="i":
    ika=lue_ika()
  if komento=="a":
    paikka=lue_paikka()
  if komento=="t":
    tulosta(nimi,ika,paikka)
  if komento=="o":
    ohje()

Chiman [10.11.2013 12:07:22]

#

Hyvä. Tyylillisesti tuossa olisi vielä parannettavaa, mutta perusharjoituksessa se ei ole niin olennaista. Tärkeintä on, että ohjelma toimii kuten pitää.

Näytän kuitenkin jatkoa varten miten tuo tulostaminen sujuu pythonmaisesti, listaa hyödyntäen.

def tulosta(nimi, ika, paikka):
    tuloste = []
    if nimi is not None:
        tuloste.append('Nimi: ' + nimi)
    if ika is not None:
        tuloste.append('Ikä: ' + str(ika))
    if paikka is not None:
        tuloste.append('Asuinpaikka: ' + paikka)
    print('\n'.join(tuloste))

Tai vielä tiiviimmin:

def tulosta(nimi, ika, paikka):
    tiedot = (('Nimi', nimi), ('Ikä', ika), ('Asuinpaikka', paikka))
    tuloste = '\n'.join('%s: %s' % (s, x) for s, x in tiedot if x)
    print(tuloste)

Jaska [10.11.2013 18:43:09]

#

Chiman kirjoitti:

Hyvä. Tyylillisesti tuossa olisi vielä parannettavaa, mutta perusharjoituksessa se ei ole niin olennaista.

Niin. Tyylejäkin on monenlaisia. Kurssilla sanottiin, että ohjelmakoodi tulisi alkaa rivillä

# -*- coding: utf-8 -*-

Toisaalta PEP8:n tyyliohjeessa tuota ei suositella. Mutta enpä olisi keksinyt googlata tuota tyyliohjetta ilman edellistä viestiäsi.

The Alchemist [10.11.2013 18:51:41]

#

Jos tää on edelleen sitä samaa kurssia, jonka vetäjä tuntui olevan täysin pihalla pythonista, niin eipä tarvitse ihmetellä.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta