"Ei sillä tietenkään ole mitään väliä tehtävän kontekstissa, mutta aloittelevat koodarit, jotka tehtäviä tekevät, alkavat luulla, että tuollainen täysin turha perusluokka pitäisi aina tehdä "hyvän tavan vuoksi" tai koska sillä saattaa olla jokin tekninen aloittelijalle tuntematon tekninen peruste. Olisi ollut aika helppoa keksiä tehtävänanto, jossa koodia ei tule juurikaan lisää mutta joka on ajatuksen tasolla paljon järkevämpi."
Tätä en epäile yhtään. Jos on tehnyt kirjan tehtävät tuohon mennessä, niin pitäisi ymmärtää tuo.
"Kysehän on siis kaksisuuntaisesta one-to-many-assosiaatiosta. Oikeassa ohjelmakoodissa se tarkoittaa sitä, että jos luokan A olio saa viitteen luokan B-olioon mutta ei toisin päin, niin ohjelmassa on hyvin todennäköisesti bugi ja siitä voi seurata esimerkiksi ohjelman kaatuminen tai kielestä riippuen vaikka muistivuoto."
Eli tässä teit tämän?
"Toimiva ohjelmakoodi olisi tällainen:
"
Yritin ajaa tehtävää koodillasi:
pong = Pong()
ping = Ping()
pong.add_ping(ping)
tulee virhe ilmoitus:
Mikähän mättää?
"Siis: sekä Ping- että Pong-luokan assosiaation rakentava metodi varmistaisi, että sekä Ping.pong että Pong.pings ovat aina ajan tasalla, eli että ei ole "orpoja" Ping-instansseja, joilla olisi viite Pong-olioon ilman että sama Pong-olio omaa viitteen kyseiseen Ping-olioon ja toisin päin."
Ei tuossa alkuperäisessä ole mitään orpoja instansseja?
pong-olio sisältää viitteitä rajattomasti pingiin ja samoin ping-olio pongiin.
"(Huomaa, että loputtoman rekursion välttämiseksi on metodeissa myös tarkistettava, että onko viite jo rakennettu, ennen kuin kutsutaan vastakkaisen luokan metodia. Ilman tarkistusta siitä seuraa ikuinen ping-pong-efekti. Oliko se sittenkin syy, miksi luokat on nimetty näin?)"
Jaahas taisit keksiä?
"Ensinnäkin sinä keksit ihan itse tuon "attribuuttijonolla" kikkailun. En nähnyt koko kirjassa muita viittauksia samaan harjoitukseen tai että samaa koodia olisi käytetty myöhemmin kirjassa."
On totta ettei tehtävänannossa pyydetty perehtymään ohjelman sielunelämään kuin kaavion verran, mutta jäi häiritsemään ohjelman kulku, joten lisäsin muutaman print()-rivin, en ole mitään keksinyt, ohjelman on ihan sama kuin kirjassa.
"Toisekseen oikeassa ohjelmakoodissa härpäkkeen tarkoitus ei varmastikaan olisi rakentaa hyvin arkista one-to-many-linkitystä vaan se olisi lähinnä vaatimus jonkin oikean toiminnallisuuden toteuttamiseksi, yksi monista välivaiheista."
No tämä ei sitten ollut se "oikea" ohjelma siihen tarkoitukseen.
"Miksei luokkia olisi voinut nimetä vaikka näin:
"
tuossa pitäisi kai olla:
"Miksei luokkia olisi voinut nimetä vaikka näin?"
Sen pingpong efektin takia?
"(Huomaa myös, ettei minun koodissani eikä alkuperäisessäkään esimerkissä kutsuta isäntäluokan konstruktoria aliluokasta vaikka niin pitäisi tehdä. Jälleen yksi aika iso virhe opetusmateriaalissa.)"
Tätä ei ole vielä kirjassa käsitelty. PingPongParent ei myöskään sisällä konstruktoria.
Tätä en epäile yhtään. Jos on tehnyt kirjan tehtävät tuohon mennessä, niin pitäisi ymmärtää tuo.
"Kysehän on siis kaksisuuntaisesta one-to-many-assosiaatiosta. Oikeassa ohjelmakoodissa se tarkoittaa sitä, että jos luokan A olio saa viitteen luokan B-olioon mutta ei toisin päin, niin ohjelmassa on hyvin todennäköisesti bugi ja siitä voi seurata esimerkiksi ohjelman kaatuminen tai kielestä riippuen vaikka muistivuoto."
Eli tässä teit tämän?
"Toimiva ohjelmakoodi olisi tällainen:
Python:
class Ping:
def set_pong(self, pong):
if not self.pong:
self.pong = pong
pong.add_ping(self)
class Pong:
def add_ping(self, ping):
if ping not in self.pings:
self.pings.append(ping)
ping.set_pong(self)
Yritin ajaa tehtävää koodillasi:
pong = Pong()
ping = Ping()
pong.add_ping(ping)
tulee virhe ilmoitus:
Koodi:
Traceback (most recent call last):
File "/home/user/Työpöytä/delme.py", line 16, in <module>
pong.add_ping(ping)
File "/home/user/Työpöytä/delme.py", line 10, in add_ping
if ping not in self.pings:
AttributeError: 'Pong' object has no attribute 'pings'
"Siis: sekä Ping- että Pong-luokan assosiaation rakentava metodi varmistaisi, että sekä Ping.pong että Pong.pings ovat aina ajan tasalla, eli että ei ole "orpoja" Ping-instansseja, joilla olisi viite Pong-olioon ilman että sama Pong-olio omaa viitteen kyseiseen Ping-olioon ja toisin päin."
Ei tuossa alkuperäisessä ole mitään orpoja instansseja?
pong-olio sisältää viitteitä rajattomasti pingiin ja samoin ping-olio pongiin.
"(Huomaa, että loputtoman rekursion välttämiseksi on metodeissa myös tarkistettava, että onko viite jo rakennettu, ennen kuin kutsutaan vastakkaisen luokan metodia. Ilman tarkistusta siitä seuraa ikuinen ping-pong-efekti. Oliko se sittenkin syy, miksi luokat on nimetty näin?)"
Jaahas taisit keksiä?
"Ensinnäkin sinä keksit ihan itse tuon "attribuuttijonolla" kikkailun. En nähnyt koko kirjassa muita viittauksia samaan harjoitukseen tai että samaa koodia olisi käytetty myöhemmin kirjassa."
On totta ettei tehtävänannossa pyydetty perehtymään ohjelman sielunelämään kuin kaavion verran, mutta jäi häiritsemään ohjelman kulku, joten lisäsin muutaman print()-rivin, en ole mitään keksinyt, ohjelman on ihan sama kuin kirjassa.
"Toisekseen oikeassa ohjelmakoodissa härpäkkeen tarkoitus ei varmastikaan olisi rakentaa hyvin arkista one-to-many-linkitystä vaan se olisi lähinnä vaatimus jonkin oikean toiminnallisuuden toteuttamiseksi, yksi monista välivaiheista."
No tämä ei sitten ollut se "oikea" ohjelma siihen tarkoitukseen.
"Miksei luokkia olisi voinut nimetä vaikka näin:
Python:
class Organism:
pass
class Tree(Organism):
def __init__(self):
self.apples = []
def add_apple(self, apple):
pass
class Apple(Organism):
def set_tree(self, tree):
pass
tuossa pitäisi kai olla:
Koodi:
def add_apple(self, apple):
self.apples.append(apple)
"Miksei luokkia olisi voinut nimetä vaikka näin?"
Sen pingpong efektin takia?
"(Huomaa myös, ettei minun koodissani eikä alkuperäisessäkään esimerkissä kutsuta isäntäluokan konstruktoria aliluokasta vaikka niin pitäisi tehdä. Jälleen yksi aika iso virhe opetusmateriaalissa.)"
Tätä ei ole vielä kirjassa käsitelty. PingPongParent ei myöskään sisällä konstruktoria.