Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: Python: Generaattorifunktio (pinta-ala)

koodaaja [24.11.2021 21:45:01]

#

Tämä ohjelma käyttää generaattorifunktiota, joka näyttää aina seuraavan tuloksen next()-funktiolla. Tässä esimerkissä käytetään pinta-alan ja piirin laskemista.

import math

#Muodostetaan kaksi funktiota ensimmäinen laskee pinta-alan ja toinen piirin.

def LaskePintaAla(sivu,valinta):
 pintaAla = 0.0
 if (valinta == 1):
  pintaAla = math.pi*sivu**2
 else:
  pintaAla = sivu*sivu
  if (valinta == 3):
   pintaAla = 0.5*pintaAla

 return pintaAla

def LaskePiiri(sivu, valinta):
 piiri = 0.0

 if (valinta == 1):
  piiri = 2*math.pi*sivu

 elif (valinta == 2):
  piiri = 4*sivu
 elif (valinta == 3):
  piiri = 2*sivu
  piiri += math.sqrt(2*sivu**2)
 return piiri

valinta = 0

print("Valitse:")
print("1) Ympyrän pinta-ala/piiri")
print("2) Neliön pinta-ala/piiri")
print("3) Kolmion pinta-ala/piiri")
valinta = int(input())

print("Anna pinta-alojen ja piirien määrä")
maara = int(input())

#Muodostamme kaksi generaattoria ensimmäiseen tallennetaan pinta-alat ja toiseen piirit.
pinta_alat = (LaskePintaAla(i,valinta) for i in range(1,maara,1))
piirit = (LaskePiiri(i,valinta) for i in range(1,maara,1))



nayta = 1

while (nayta != 0):
 #Näytetään seuraava pinta-ala tai piiri.
 print("Valitse")
 print("1) Seuraava pinta-ala")
 print("2) Seuraava piiri")
 print("0) Lopeta")
 nayta = int(input())
 if (nayta== 1):
  print(next(pinta_alat))
 elif (nayta == 2):
  print(next(piirit))

Metabolix [25.11.2021 21:46:45]

#

Olet ymmärtänyt jotain väärin. Generaattorifunktio olisi funktio, jossa yield-lauseella tuotetaan lisää arvoja. Sen sijaan for-rakenne on generaattorilauseke. Lisäksi vastoin koodisi kommenttia generaattorin idea on juuri se, että tiedot eivät ole siinä tallennettuina (kuten listassa olisi) vaan niitä lasketaan tarpeen mukaan lisää. Funktiolle ei myöskään tarvita ylärajaa, kuten lausekkeellasi on.

Eli generaattorifunktioilla koodissasi silmukka (yleensä while-silmukka) olisi generaattorifunktion sisällä, silmukassa yield palauttaisi aina lisää arvoja, ja piirit/pinta_alat alustettaisiin vain yhdellä funktiokutsulla:

piirit = LaskePiirit(valinta)

Koodin voisi siis oikealla generaattorifunktiolla tehdä näin:

import math
def sarja(alku, aste):
	i = 1
	while True:
		yield alku * (i ** aste)
		i += 1

tiedot = [
	("Ympyrän", "säde", math.pi, 2 * math.pi),
	("Neliön", "sivu", 1, 4),
	("Suorakulmaisen, tasakylkisen kolmion", "kateetti", 0.5, 2 + (2**0.5)),
]
print("Valitse:")
for i in range(len(tiedot)):
	print(f"{i+1}) {tiedot[i][0]} pinta-ala ja piiri")
valinta = int(input())
minkä, sivusana, ala1, piiri1 = tiedot[valinta - 1]

piiri = sarja(piiri1, 1)
ala = sarja(ala1, 2)

while True:
	print(f"Piiri on {next(piiri)} ja pinta-ala {next(ala)}.")
	print("0) Lopeta, 1) Jatka.")
	if (input() == "0"):
		break

Toisaalta generaattorifunktio on aika turha, koska generaattorilausekkeella voisi tehdä näin:

piiri = (piiri1 * i for i in range(1, 1 << 100))
ala = (ala1 * (i * i) for i in range(1, 1 << 100))

(1 << 100 on iso luku, jolloin range on käytännön tarkoituksiin ääretön.)

Ylipäänsä koko generaattori on lähinnä vain häiriöksi, kun siinä häviää tieto, mitä oikeastaan edes lasketaan. (Alkuperäisessä koodissasi annat selata pinta-aloja ja piirejä eri tahtiin, mikä on lähinnä järjetöntä.) Ilman erillisiä generaattoreita voisi tehdä paljon järkevämmän silmukan:

for i in range(1, 1 << 100):
	piiri = piiri1 * i
	ala = ala1 * (i * i)
	print(f"{minkä} {sivusana} on {i}, jolloin piiri on {piiri} ja pinta-ala {ala}.")
	print("0) Lopeta, 1) Jatka.")
	if (input() == "0"):
		break

Huomaa myös, että tässä koodissa ei törttöillä valinta-lukuarvon kanssa muualla, vaan heti syötteen lukemisen jälkeen heitetään kyseinen merkityksetön lukuarvo pois ja käytetään niitä tietoja, jotka käyttäjä on kyseisellä luvulla valinnut.

Vastaus

Muista lukea kirjoitusohjeet.
Tietoa sivustosta