Informatika2-2015/Eloadas 2 Python-2 Rekurzio es Ciklus

A MathWikiből
(Változatok közti eltérés)
 
(egy szerkesztő 2 közbeeső változata nincs mutatva)
1. sor: 1. sor:
=Bemutatkozás=
 
* Eisenberger András
 
* Hívjatok Csirkének
 
* email: [mailto:csirkeee@gmail.com csirkeee@gmail.com]
 
 
=Python ismétlés=
 
 
Aki nem 2014-ben hallgatta az Info1-et és úgy érzi lemaradása van, azok részére elérhetőek
 
* Az előző félév előadásainak anyagai: [[Informatika1-2014/eloadas3]], [[Informatika1-2014/eloadas4]]
 
* Vagy akár a hivatalos (angol) Python tanító anyag: [http://docs.python.org/2.7/tutorial/ Python tutorial].
 
 
Mai órán még kb. elég az [[Informatika1-2014/eloadas3|eloadas3]] anyaga, ami kell az függvények definiálása, elágazások.
 
 
A Python nagyon népszerű nyelv, többek között jól átlátható szintaxisa miatt, és mivel viszonylag könnyű új platformokra is átültetni. Ennek köszönhető, hogy rengeteg eszköz és erőforrás elérhető hozzá az interneten. Csak egy példa a http://pythontutor.com, amit itt az előadás lapjain is használunk a kód részletes bemutatásához, de ti is használhatjátok saját teszteléshez.
 
  
 
==Függvényhívás példa==
 
==Függvényhívás példa==
  
Python-ban a kódban bárhol definiálható függvény a kódban, a <code>def</code> kulcsszóval. Egyelőre most arról az esetről beszélünk csak, amikor a fájl gyökerében van definiálva, nem másik függvényen belül.
+
Múlt órán volt részletesen szó függvényhívásról. Itt egy példa:
  
 
<wikiframe width="800" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+negyzet(k)%3A%0A++++return+k*k%0A%0Adef+negyzetel(l)%3A%0A++++for+i+in+range(len(l))%3A%0A++++++++l%5Bi%5D+%3D+negyzet(l%5Bi%5D)%0A++++return+l%0A++++%0Aszamok+%3D+%5B2,+3,+4%5D%0Aprint+negyzetel(szamok)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400"/>
 
<wikiframe width="800" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+negyzet(k)%3A%0A++++return+k*k%0A%0Adef+negyzetel(l)%3A%0A++++for+i+in+range(len(l))%3A%0A++++++++l%5Bi%5D+%3D+negyzet(l%5Bi%5D)%0A++++return+l%0A++++%0Aszamok+%3D+%5B2,+3,+4%5D%0Aprint+negyzetel(szamok)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+negyzet(k)%3A%0A++++return+k*k%0A%0Adef+negyzetel(l)%3A%0A++++for+i+in+range(len(l))%3A%0A++++++++l%5Bi%5D+%3D+negyzet(l%5Bi%5D)%0A++++return+l%0A++++%0Aszamok+%3D+%5B2,+3,+4%5D%0Aprint+negyzetel(szamok)&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
  
 
Amit érdemes megfigyelni, hogy amikor a <code>negyzetel()</code> függvény meghívja a <code>negyzet()</code> függvényt (pl. Step 8-nál), amíg a <code>negyzet()</code> fut, a <code>negyzetel()</code> még nem ért véget, csak fel lett függesztve azon a ponton, ahol vár a <code>negyzet()</code> visszatérési értékére, majd onnan folytatódik.
 
Amit érdemes megfigyelni, hogy amikor a <code>negyzetel()</code> függvény meghívja a <code>negyzet()</code> függvényt (pl. Step 8-nál), amíg a <code>negyzet()</code> fut, a <code>negyzetel()</code> még nem ért véget, csak fel lett függesztve azon a ponton, ahol vár a <code>negyzet()</code> visszatérési értékére, majd onnan folytatódik.
  
 
=Ciklus vagy rekurzió=
 
=Ciklus vagy rekurzió=
 +
 +
A mai órán két programozási módszerről lesz szó, amik már előző félévben is szerepeltek valamennyire. Megvizsgáljuk a különbségeket és hasonlóságokat, így talán jobban megértjük mindkettőt.
 +
 +
Először nézzünk egy nagyon egyszerű példát hogy felfrissítsük is hogy hogy működnek a cilusok és a rekurzív függvények:
  
 
==Faktoriális kiszámolása==
 
==Faktoriális kiszámolása==
28. sor: 19. sor:
  
 
<wikiframe  width="800" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+fakt_ciklus(n)%3A%0A++++fakt+%3D+1%0A++++i+%3D+1%0A++++while+i+%3C%3D+n%3A%0A++++++++fakt+%3D+i+*+fakt%0A++++++++i+%3D+i+%2B+1%0A++++return+fakt%0A%0Aprint+fakt_ciklus(5)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400"/>
 
<wikiframe  width="800" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+fakt_ciklus(n)%3A%0A++++fakt+%3D+1%0A++++i+%3D+1%0A++++while+i+%3C%3D+n%3A%0A++++++++fakt+%3D+i+*+fakt%0A++++++++i+%3D+i+%2B+1%0A++++return+fakt%0A%0Aprint+fakt_ciklus(5)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+fakt_ciklus(n)%3A%0A++++fakt+%3D+1%0A++++i+%3D+1%0A++++while+i+%3C%3D+n%3A%0A++++++++fakt+%3D+i+*+fakt%0A++++++++i+%3D+i+%2B+1%0A++++return+fakt%0A%0Aprint+fakt_ciklus(5)&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
  
 
A ciklus kódjának végére érve bizonyos feltétel mellett visszaugrunk a ciklus kódjának elejére, de bizonyos elérhető változók értéke megváltozott.
 
A ciklus kódjának végére érve bizonyos feltétel mellett visszaugrunk a ciklus kódjának elejére, de bizonyos elérhető változók értéke megváltozott.
34. sor: 26. sor:
  
 
<wikiframe width="900" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+fakt_rekurziv(n)%3A%0A++++if+n+%3D%3D+1%3A%0A++++++++return+1%0A++++else%3A%0A++++++++return+n+*+fakt_rekurziv(n-1)%0A%0Aprint+fakt_rekurziv(5)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=450&codeDivHeight=400"/>
 
<wikiframe width="900" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+fakt_rekurziv(n)%3A%0A++++if+n+%3D%3D+1%3A%0A++++++++return+1%0A++++else%3A%0A++++++++return+n+*+fakt_rekurziv(n-1)%0A%0Aprint+fakt_rekurziv(5)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=450&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+fakt_rekurziv(n)%3A%0A++++if+n+%3D%3D+1%3A%0A++++++++return+1%0A++++else%3A%0A++++++++return+n+*+fakt_rekurziv(n-1)%0A%0Aprint+fakt_rekurziv(5)&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
  
 
Ebben az esetben a függvény végén bizonyos feltétel mellett visszaugrom a függvény kódjának elejére (meghívom a függvényt), de bizonyos elérhető változók (a függvény paraméterei) értéke megváltozott.
 
Ebben az esetben a függvény végén bizonyos feltétel mellett visszaugrom a függvény kódjának elejére (meghívom a függvényt), de bizonyos elérhető változók (a függvény paraméterei) értéke megváltozott.
46. sor: 39. sor:
  
 
<wikiframe width="800" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+szorzotabla_ciklus(a,+b)%3A%0A++++for+i+in+range(1,+a%2B1)%3A%0A++++++++for+j+in+range(1,+b%2B1)%3A%0A++++++++++++print+i*j,%0A++++++++print%0A++++++++%0Aszorzotabla_ciklus(3,+4)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400"/>
 
<wikiframe width="800" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+szorzotabla_ciklus(a,+b)%3A%0A++++for+i+in+range(1,+a%2B1)%3A%0A++++++++for+j+in+range(1,+b%2B1)%3A%0A++++++++++++print+i*j,%0A++++++++print%0A++++++++%0Aszorzotabla_ciklus(3,+4)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=350&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+szorzotabla_ciklus(a,+b)%3A%0A++++for+i+in+range(1,+a%2B1)%3A%0A++++++++for+j+in+range(1,+b%2B1)%3A%0A++++++++++++print+i*j,%0A++++++++print%0A++++++++%0Aszorzotabla_ciklus(3,+4)&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
  
 
Ha ennek próbáljuk az analógiáját megcsinálni rekurzívan, meg lehet, de bonyolult kódot kapunk:
 
Ha ennek próbáljuk az analógiáját megcsinálni rekurzívan, meg lehet, de bonyolult kódot kapunk:
  
 
<wikiframe width="1000" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+szorzotabla_rekurziv_belso(i,+j,+a,+b)%3A%0A++++print+i*j,%0A++++if+j+%3C+b%3A%0A++++++++szorzotabla_rekurziv_belso(i,+j%2B1,+a,+b)%0A++++elif+i+%3C+a%3A%0A++++++++print%0A++++++++szorzotabla_rekurziv_belso(i%2B1,+1,+a,+b)%0A%0Adef+szorzotabla_rekurziv(a,+b)%3A%0A++++szorzotabla_rekurziv_belso(1,+1,+a,+b)%0A++++++++%0Aszorzotabla_rekurziv(3,+4)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=600&codeDivHeight=400"/>
 
<wikiframe width="1000" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+szorzotabla_rekurziv_belso(i,+j,+a,+b)%3A%0A++++print+i*j,%0A++++if+j+%3C+b%3A%0A++++++++szorzotabla_rekurziv_belso(i,+j%2B1,+a,+b)%0A++++elif+i+%3C+a%3A%0A++++++++print%0A++++++++szorzotabla_rekurziv_belso(i%2B1,+1,+a,+b)%0A%0Adef+szorzotabla_rekurziv(a,+b)%3A%0A++++szorzotabla_rekurziv_belso(1,+1,+a,+b)%0A++++++++%0Aszorzotabla_rekurziv(3,+4)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=600&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+szorzotabla_rekurziv_belso(i,+j,+a,+b)%3A%0A++++print+i*j,%0A++++if+j+%3C+b%3A%0A++++++++szorzotabla_rekurziv_belso(i,+j%2B1,+a,+b)%0A++++elif+i+%3C+a%3A%0A++++++++print%0A++++++++szorzotabla_rekurziv_belso(i%2B1,+1,+a,+b)%0A%0Adef+szorzotabla_rekurziv(a,+b)%3A%0A++++szorzotabla_rekurziv_belso(1,+1,+a,+b)%0A++++++++%0Aszorzotabla_rekurziv(3,+4)&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
  
Egy másik hátrány amit valamennyire mutat az előző kódrészlet, hogy ilyenkor a végére a függvény összes változata egyszerre fut. Ez nem minden programozási nyelven, és nem mindig igaz, de ha igen, akkor jelentősen több memóriát foglal ez a változat, mint a ciklussal megírt változat.
+
Látható, hogy az '''i''' és '''j''' változókat is a függvény paraméterévé kellett tenni, hogy elérhetőek legyenek a belső kódban.
 +
 
 +
Egy másik hátrány amit valamennyire mutat az előző kódrészlet, ha megnézzük a Python Tutor-on a futását, hogy ilyenkor a végére a függvény összes változata egyszerre fut. Ez nem minden programozási nyelven, és nem mindig, igaz, de ha igen, akkor jelentősen több memóriát foglal ez a változat, mint a ciklussal megírt változat.
  
 
Mivel rekurziónál a régebben kiszámolt értékek lehet hogy nem elérhetőek, ezért a gondtalanul megírt rekurzív kód lehet hogy fölöslegesen sokat számol. Példának itt van ez a '''rosszul megírt''' változata a fibonacci számok kiszámolásának:
 
Mivel rekurziónál a régebben kiszámolt értékek lehet hogy nem elérhetőek, ezért a gondtalanul megírt rekurzív kód lehet hogy fölöslegesen sokat számol. Példának itt van ez a '''rosszul megírt''' változata a fibonacci számok kiszámolásának:
  
 
<wikiframe width="1000" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+fibonacci_rekurziv(n)%3A%0A++++if+n+%3D%3D+1%3A%0A++++++++return+1%0A++++elif+n+%3D%3D+2%3A%0A++++++++return+1%0A++++else%3A%0A++++++++return+(fibonacci_rekurziv(n-1)+%2B%0A++++++++++++fibonacci_rekurziv(n-2))%0A%0Aprint+fibonacci_rekurziv(5)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=550&codeDivHeight=400"/>
 
<wikiframe width="1000" height="500" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+fibonacci_rekurziv(n)%3A%0A++++if+n+%3D%3D+1%3A%0A++++++++return+1%0A++++elif+n+%3D%3D+2%3A%0A++++++++return+1%0A++++else%3A%0A++++++++return+(fibonacci_rekurziv(n-1)+%2B%0A++++++++++++fibonacci_rekurziv(n-2))%0A%0Aprint+fibonacci_rekurziv(5)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=550&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+fibonacci_rekurziv(n)%3A%0A++++if+n+%3D%3D+1%3A%0A++++++++return+1%0A++++elif+n+%3D%3D+2%3A%0A++++++++return+1%0A++++else%3A%0A++++++++return+(fibonacci_rekurziv(n-1)+%2B%0A++++++++++++fibonacci_rekurziv(n-2))%0A%0Aprint+fibonacci_rekurziv(5)&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
  
 
Végigléptetve, a <code>fibonacci_rekurziv(3)</code> meg van hívva a 11-es és a 34-es lépésnél is, és mindkétszer újra ki van számolva. A matematikai gondolkodásmód szerint ugyan igaz hogy mindkét esetben a 3. fibonacci szám értékére van szükség, de programozásnál azt is végig kell gondolni hogy ez milyen lépésekkel fog járni.
 
Végigléptetve, a <code>fibonacci_rekurziv(3)</code> meg van hívva a 11-es és a 34-es lépésnél is, és mindkétszer újra ki van számolva. A matematikai gondolkodásmód szerint ugyan igaz hogy mindkét esetben a 3. fibonacci szám értékére van szükség, de programozásnál azt is végig kell gondolni hogy ez milyen lépésekkel fog járni.
  
Összességében a ciklus mindenképp könnyebben használható ha sok változóra van szükség a kód belsejében, beleértve ha egy táblázatot töltünk fel, és annak a régebbi elemeiről van szó. Olyan esetben is érdemesebb használni mint a rekurziót, amikor a rekurzió mélysége (hány példánya fut a függvénynek egyszerre) nagyon megnőhetne, mert az a hatékonyságot csökkenti nagy memódiaigényével.
+
Összességében a ciklus mindenképp könnyebben használható ha:
 +
* sok változóra van szükség a kód belsejében
 +
* egy táblázatot töltünk fel
 +
* a ciklus sok egymástól független elemmel dolgozik
 +
Olyan esetben is érdemesebb ciklust használni mint rekurziót, amikor a rekurzió mélysége (hány példánya fut a függvénynek egyszerre) nagyon megnőhetne, mert az a hatékonyságot csökkenti nagy memóriaigényével.
  
 
==Rekurzió előnyei==
 
==Rekurzió előnyei==
70. sor: 72. sor:
  
 
<wikiframe width="1150" height="650" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+osztosor_rekurziv_belso(k,+l)%3A%0A++++print+l+%2B+%5B1%5D%0A++++for+i+in+range(2,+k)%3A%0A++++++++if+k+%25+i+%3D%3D+0%3A%0A++++++++++++osztosor_rekurziv_belso(i,+l+%2B+%5Bi%5D)%0A%0Adef+osztosor_rekurziv(k)%3A%0A++++osztosor_rekurziv_belso(k,+%5Bk%5D)%0A%0Aosztosor_rekurziv(12)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=550&codeDivHeight=400"/>
 
<wikiframe width="1150" height="650" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+osztosor_rekurziv_belso(k,+l)%3A%0A++++print+l+%2B+%5B1%5D%0A++++for+i+in+range(2,+k)%3A%0A++++++++if+k+%25+i+%3D%3D+0%3A%0A++++++++++++osztosor_rekurziv_belso(i,+l+%2B+%5Bi%5D)%0A%0Adef+osztosor_rekurziv(k)%3A%0A++++osztosor_rekurziv_belso(k,+%5Bk%5D)%0A%0Aosztosor_rekurziv(12)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=550&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+osztosor_rekurziv_belso(k,+l)%3A%0A++++print+l+%2B+%5B1%5D%0A++++for+i+in+range(2,+k)%3A%0A++++++++if+k+%25+i+%3D%3D+0%3A%0A++++++++++++osztosor_rekurziv_belso(i,+l+%2B+%5Bi%5D)%0A%0Adef+osztosor_rekurziv(k)%3A%0A++++osztosor_rekurziv_belso(k,+%5Bk%5D)%0A%0Aosztosor_rekurziv(12)&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
  
 
Próbáljuk meg ugyanezt a megoldást reprodukálni ciklussal. Itt egy ilyen megoldás:
 
Próbáljuk meg ugyanezt a megoldást reprodukálni ciklussal. Itt egy ilyen megoldás:
  
 
<wikiframe width="1150" height="1000" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+osztosor_ciklus(k)%3A%0A++++l+%3D+%5Bk,+1%5D%0A++++while+1%3A%0A++++++++%23+Kiirjuk+az+uj+osztosort%0A++++++++print+l%0A++++++++while+len(l)+%3E+1%3A%0A++++++++++++%23+Noveljuk+az+utolso+elemet%0A++++++++++++l%5B-1%5D+%3D+l%5B-1%5D+%2B+1%0A++++++++++++%23+Ha+az+utolso+elem+megegyezik+az%0A++++++++++++%23+utolso+elottivel,+vissza+kell+lepnunk,%0A++++++++++++%23+roviditeni+a+listat%0A++++++++++++if+l%5B-1%5D+%3D%3D+l%5B-2%5D%3A%0A++++++++++++++++del+l%5B-1%5D%0A++++++++++++%23+Ha+az+utolso+elem+az+utolso+elotti%0A++++++++++++%23+osztoja,+a+vegere+1-est+teve+uj%0A++++++++++++%23+osztosort+talaltunk%0A++++++++++++elif+l%5B-2%5D+%25+l%5B-1%5D+%3D%3D+0%3A%0A++++++++++++++++l.append(1)%0A++++++++++++++++break%0A++++++++%23+Amikor+a+lista+1+elemure+rovidult,+mindent%0A++++++++%23+megtalaltunk.%0A++++++++else%3A%0A++++++++++++return%0A%0Aosztosor_ciklus(12)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=580&codeDivHeight=650"/>
 
<wikiframe width="1150" height="1000" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+osztosor_ciklus(k)%3A%0A++++l+%3D+%5Bk,+1%5D%0A++++while+1%3A%0A++++++++%23+Kiirjuk+az+uj+osztosort%0A++++++++print+l%0A++++++++while+len(l)+%3E+1%3A%0A++++++++++++%23+Noveljuk+az+utolso+elemet%0A++++++++++++l%5B-1%5D+%3D+l%5B-1%5D+%2B+1%0A++++++++++++%23+Ha+az+utolso+elem+megegyezik+az%0A++++++++++++%23+utolso+elottivel,+vissza+kell+lepnunk,%0A++++++++++++%23+roviditeni+a+listat%0A++++++++++++if+l%5B-1%5D+%3D%3D+l%5B-2%5D%3A%0A++++++++++++++++del+l%5B-1%5D%0A++++++++++++%23+Ha+az+utolso+elem+az+utolso+elotti%0A++++++++++++%23+osztoja,+a+vegere+1-est+teve+uj%0A++++++++++++%23+osztosort+talaltunk%0A++++++++++++elif+l%5B-2%5D+%25+l%5B-1%5D+%3D%3D+0%3A%0A++++++++++++++++l.append(1)%0A++++++++++++++++break%0A++++++++%23+Amikor+a+lista+1+elemure+rovidult,+mindent%0A++++++++%23+megtalaltunk.%0A++++++++else%3A%0A++++++++++++return%0A%0Aosztosor_ciklus(12)&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=580&codeDivHeight=650"/>
 +
[http://pythontutor.com/visualize.html#code=def+osztosor_ciklus(k)%3A%0A++++l+%3D+%5Bk,+1%5D%0A++++while+1%3A%0A++++++++%23+Kiirjuk+az+uj+osztosort%0A++++++++print+l%0A++++++++while+len(l)+%3E+1%3A%0A++++++++++++%23+Noveljuk+az+utolso+elemet%0A++++++++++++l%5B-1%5D+%3D+l%5B-1%5D+%2B+1%0A++++++++++++%23+Ha+az+utolso+elem+megegyezik+az%0A++++++++++++%23+utolso+elottivel,+vissza+kell+lepnunk,%0A++++++++++++%23+roviditeni+a+listat%0A++++++++++++if+l%5B-1%5D+%3D%3D+l%5B-2%5D%3A%0A++++++++++++++++del+l%5B-1%5D%0A++++++++++++%23+Ha+az+utolso+elem+az+utolso+elotti%0A++++++++++++%23+osztoja,+a+vegere+1-est+teve+uj%0A++++++++++++%23+osztosort+talaltunk%0A++++++++++++elif+l%5B-2%5D+%25+l%5B-1%5D+%3D%3D+0%3A%0A++++++++++++++++l.append(1)%0A++++++++++++++++break%0A++++++++%23+Amikor+a+lista+1+elemure+rovidult,+mindent%0A++++++++%23+megtalaltunk.%0A++++++++else%3A%0A++++++++++++return%0A%0Aosztosor_ciklus(12)&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
  
Ez a legegyszerűbb kód amit sikerült írnom, és még így is a kommentekkel együtt sem vagyok benne teljesen biztos hogy jól érthető.
+
Ez a legegyszerűbb kód amit sikerült írnom, és még így is a kommentekkel együtt sem vagyok benne teljesen biztos hogy jól érthető. Itt van kommentek nélkül is, hogy látható legyen hogy mennyivel hosszabb és bonyolultabb:
 +
 
 +
<python>def osztosor_ciklus(k):
 +
    l = [k, 1]
 +
    while 1:
 +
        print l
 +
        while len(l) > 1:
 +
            l[-1] = l[-1] + 1
 +
            if l[-1] == l[-2]:
 +
                del l[-1]
 +
            elif l[-2] % l[-1] == 0:
 +
                l.append(1)
 +
                break
 +
        else:
 +
            return</python>
 +
 
 +
Ez egy olyan feladat, amire a rekurzió alkalmasabb. Amikor ciklussal csináljuk meg ugyanazt, akkor is vigyáznunk kell, hogy a lista hányadik eleménél éppen hol tartunk, mikor kell előre illetve visszalépnünk a listában. Ezek a rekurzív változatban a függvény hívásának és visszatérésének felelnek meg, így bizonyos mértékig "automatikusan" vannak kezelve.
  
 
De amit igazán fontos megérteni, hogy '''továbbra is a ciklusos kód a hatékonyabb'''. A rekurzív kód ugyan rövidebb, és a Python Tutor szerint kevesebb lépésből áll, de:
 
De amit igazán fontos megérteni, hogy '''továbbra is a ciklusos kód a hatékonyabb'''. A rekurzív kód ugyan rövidebb, és a Python Tutor szerint kevesebb lépésből áll, de:
88. sor: 108. sor:
 
* Gráfok bejárása.
 
* Gráfok bejárása.
 
* Más olyan feladat, ahol a rekurzív változat egy ciklusban hívja önmagát.
 
* Más olyan feladat, ahol a rekurzív változat egy ciklusban hívja önmagát.
* Olyan táblázatok kitöltése, ahol a táblázatnak végül csak néhány eleme számít.
+
* Olyan táblázatok kitöltése, ahol a táblázatnak végül csak néhány eleme számít. Ilyenkor úgynevezett letárolásos rekurziót használunk.
 
* Olyan problémáknál, ahol a kimenet maga rekurzív jellegű. Ilyen példa az osztósoros feladat, vagy fraktálok kirajzolása, különféle természetes folyamatok szimulációja.
 
* Olyan problémáknál, ahol a kimenet maga rekurzív jellegű. Ilyen példa az osztósoros feladat, vagy fraktálok kirajzolása, különféle természetes folyamatok szimulációja.
  
 
Nézünk majd példákat a gyakorlaton.
 
Nézünk majd példákat a gyakorlaton.
 +
 +
= Mutable és Immutable típusok =
 +
A pythonban két fajta változó van, mutable (kb. "változtatható"), és immutable (kb. "nem változtatható"). (Inkább az angol neveket használom, mert annak hogy nem változtatható változó nincs értelme, legalábbis nem az, amit igazából jelent az immutable.)
 +
 +
== Immutable ==
 +
 +
Az immutable változó az egyszerűbb eset, ez az olyan változó, amiben bízhatunk, hogy csak akkor változik az értéke, ha mi értéket adunk neki:
 +
 +
<wikiframe width="1100" height="600" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=a+%3D+5%0Ab+%3D+a%0Ab+%2B%3D+2%0Aprint+%22a%3A%22,+a%0Aprint+%22b%3A%22,+b%0A%0Anev+%3D+%22Moricka%22%0Akerdes+%3D+nev%0Akerdes+%2B%3D+%22-e%22%0Aprint+%22nev%3A%22,+nev%0Aprint+%22kerdes%3A%22,+kerdes&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=550&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=a+%3D+5%0Ab+%3D+a%0Ab+%2B%3D+2%0Aprint+%22a%3A%22,+a%0Aprint+%22b%3A%22,+b%0A%0Anev+%3D+%22Moricka%22%0Akerdes+%3D+nev%0Akerdes+%2B%3D+%22-e%22%0Aprint+%22nev%3A%22,+nev%0Aprint+%22kerdes%3A%22,+kerdes&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
 +
 +
Itt az látható, hogy ugyan azt mondtuk, hogy "b = a", amikor utána megváltoztatjuk a ''b'' értékét, annak nincs hatása az ''a'' értékére.
 +
 +
Ilyen fajta, tehát immutable, például a:
 +
* minden féle szám, tehát egész, valós (float) vagy akár komplex
 +
* igaz/hamis (boolean) változók
 +
* karakterláncok
 +
* tuple
 +
 +
== Mutable ==
 +
 +
Kicsit nehezebb eset a mutable változók. Először nézzünk példa kódot
 +
 +
<wikiframe width="1100" height="600" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=jatekok+%3D+%5B%22Catan%22,+%22Carcassone%22,+%22Dominion%22%5D%0Ajojatekok+%3D+jatekok%0Ajojatekok%5B0%5D+%3D+%22Poker%22%0Aprint+%22jatekok%3A%22,+jatekok%0Aprint+%22jojatekok%3A%22,+jojatekok%0A%0Aosztalyzat+%3D+%7B%22Tofi%22+%3A+5%7D%0Aidei+%3D+osztalyzat%0Aidei%5B%22Csirke%22%5D+%3D+1%0Aprint+%22osztalyzat%3A%22,+osztalyzat%0Aprint+%22idei%3A%22,+idei&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=550&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=jatekok+%3D+%5B%22Catan%22,+%22Carcassone%22,+%22Dominion%22%5D%0Ajojatekok+%3D+jatekok%0Ajojatekok%5B0%5D+%3D+%22Poker%22%0Aprint+%22jatekok%3A%22,+jatekok%0Aprint+%22jojatekok%3A%22,+jojatekok%0A%0Aosztalyzat+%3D+%7B%22Tofi%22+%3A+5%7D%0Aidei+%3D+osztalyzat%0Aidei%5B%22Csirke%22%5D+%3D+1%0Aprint+%22osztalyzat%3A%22,+osztalyzat%0Aprint+%22idei%3A%22,+idei&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
 +
 +
Itt azt láthatjuk, hogy amikor megváltoztatjuk a ''jojatekok'' értékét, akkor a ''jatekok'' értéke is megváltozik. Ez azért van, mert ugyan ''jatekok'' és ''jojatekok'' két külön változó, de ugyanarra a listára hivatkoznak. Ezt a python tutor is jelzi a fenti kódábrázolásban, azzal hogy nem a változó neve mellett van a lista tartalma, hanem onnan mutat egy nyíl a listára, és ott látható a tartalom.
 +
 +
Néhány változótípus, ami mutable:
 +
* Lista
 +
* Szótár
 +
* Halmaz
 +
* Általában minden bonyolultabb dolog.
 +
 +
== Problémák ==
 +
 +
Miért fontos ez számunkra? Profibb felhasználók számára van amikor ezt jól ki tudják használni, hogy hatékony legyen a kódjuk. Azonban a jelenlegi szinten nekünk ez több problémát okoz, mint amiben segít. Ezért most arra koncentrálok, hogy hogyan tudjuk elkerülni hogy módosítsunk valamit amit nem akarunk. Egy példa:
 +
 +
<wikiframe width="1100" height="600" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+osszead(L)%3A%0A++++osszeg+%3D+0%0A++++while+L%3A%0A++++++++osszeg+%2B%3D+L%5B0%5D%0A++++++++del+L%5B0%5D%0A++++return+osszeg%0A++++%0Aszamok+%3D+%5B3,+4,+2%5D%0Aszamok_ossz+%3D+osszead(szamok)%0A%23+Ki%C3%ADrjuk+a+sz%C3%A1mokat+%C3%A9s+az+%C3%B6sszeg%C3%BCk%0Aprint+szamok,+%22,+%C3%B6sszesen%22,+szamok_ossz&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=550&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+osszead(L)%3A%0A++++osszeg+%3D+0%0A++++while+L%3A%0A++++++++osszeg+%2B%3D+L%5B0%5D%0A++++++++del+L%5B0%5D%0A++++return+osszeg%0A++++%0Aszamok+%3D+%5B3,+4,+2%5D%0Aszamok_ossz+%3D+osszead(szamok)%0A%23+Ki%C3%ADrjuk+a+sz%C3%A1mokat+%C3%A9s+az+%C3%B6sszeg%C3%BCk%0Aprint+szamok,+%22,+%C3%B6sszesen%22,+szamok_ossz&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
 +
 +
Ha csak az utolsó 4 sort olvassuk el, teljesen logikusnak tűnik a dolog, de mégsem működik, mert a függvényen belül megváltoztattuk a listát amit kaptunk. Általános megoldás amit javaslok, függvényen belül soha ne változtassunk meg olyan mutable változókat amiket paraméterként kaptunk. Ha úgy egyszerű a kódunk hogy az eredeti listából/szótárból törlünk vagy módosítunk, akkor először készítsünk egy másolatot. Például az előző kódunk javított változata így nézhet ki:
 +
 +
<wikiframe width="1100" height="600" frameborder="1" src="http://pythontutor.com/iframe-embed.html#code=def+osszead(L_be)%3A%0A++++L+%3D+L_be%5B%3A%5D%0A++++osszeg+%3D+0%0A++++while+L%3A%0A++++++++osszeg+%2B%3D+L%5B0%5D%0A++++++++del+L%5B0%5D%0A++++return+osszeg%0A++++%0Aszamok+%3D+%5B3,+4,+2%5D%0Aszamok_ossz+%3D+osszead(szamok)%0A%23+Ki%C3%ADrjuk+a+sz%C3%A1mokat+%C3%A9s+az+%C3%B6sszeg%C3%BCk%0Aprint+szamok,+%22,+%C3%B6sszesen%22,+szamok_ossz&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0&codeDivWidth=550&codeDivHeight=400"/>
 +
[http://pythontutor.com/visualize.html#code=def+osszead(L_be)%3A%0A++++L+%3D+L_be%5B%3A%5D%0A++++osszeg+%3D+0%0A++++while+L%3A%0A++++++++osszeg+%2B%3D+L%5B0%5D%0A++++++++del+L%5B0%5D%0A++++return+osszeg%0A++++%0Aszamok+%3D+%5B3,+4,+2%5D%0Aszamok_ossz+%3D+osszead(szamok)%0A%23+Ki%C3%ADrjuk+a+sz%C3%A1mokat+%C3%A9s+az+%C3%B6sszeg%C3%BCk%0Aprint+szamok,+%22,+%C3%B6sszesen%22,+szamok_ossz&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 link]
 +
 +
Lista másolásához ez a '''[:]''' jelzés általános módszer a másoláshoz, a szótárnak van egy külön '''copy()''' metódusa, amit így lehet használni:
 +
 +
<python>szotar = {"cica" : "kitten", "kutya" : "dog"}
 +
szotar_masolat = szotar.copy()</python>
 +
 +
Egyelőre ennyit elég tudni a mutable típusokról, még a félév folyamán később visszatérünk rájuk.

A lap jelenlegi, 2015. február 19., 00:24-kori változata

Tartalomjegyzék

Függvényhívás példa

Múlt órán volt részletesen szó függvényhívásról. Itt egy példa:

link

Amit érdemes megfigyelni, hogy amikor a negyzetel() függvény meghívja a negyzet() függvényt (pl. Step 8-nál), amíg a negyzet() fut, a negyzetel() még nem ért véget, csak fel lett függesztve azon a ponton, ahol vár a negyzet() visszatérési értékére, majd onnan folytatódik.

Ciklus vagy rekurzió

A mai órán két programozási módszerről lesz szó, amik már előző félévben is szerepeltek valamennyire. Megvizsgáljuk a különbségeket és hasonlóságokat, így talán jobban megértjük mindkettőt.

Először nézzünk egy nagyon egyszerű példát hogy felfrissítsük is hogy hogy működnek a cilusok és a rekurzív függvények:

Faktoriális kiszámolása

Ciklus:

link

A ciklus kódjának végére érve bizonyos feltétel mellett visszaugrunk a ciklus kódjának elejére, de bizonyos elérhető változók értéke megváltozott.

Rekurzió:

link

Ebben az esetben a függvény végén bizonyos feltétel mellett visszaugrom a függvény kódjának elejére (meghívom a függvényt), de bizonyos elérhető változók (a függvény paraméterei) értéke megváltozott.

Ennél a példánál láthatóak a hasonlóságok a kettő között, de mik a különbségek?

Ciklus előnyei

A ciklus fontos előnye, hogy nem hoz egy új névteret létre: minden változó amit a függvényben használtunk, elérhető a cikluson belül is. Ezzel ellenben ha egy függvényt, akár önmagát, hívjuk, akkor ott csak azok a változók érhetőek el, amiket paraméterként átadunk.

Emiatt, ha pl. egy táblázatot akarunk kitölteni, akkor azt ciklussal nagyon egyszerű:

link

Ha ennek próbáljuk az analógiáját megcsinálni rekurzívan, meg lehet, de bonyolult kódot kapunk:

link

Látható, hogy az i és j változókat is a függvény paraméterévé kellett tenni, hogy elérhetőek legyenek a belső kódban.

Egy másik hátrány amit valamennyire mutat az előző kódrészlet, ha megnézzük a Python Tutor-on a futását, hogy ilyenkor a végére a függvény összes változata egyszerre fut. Ez nem minden programozási nyelven, és nem mindig, igaz, de ha igen, akkor jelentősen több memóriát foglal ez a változat, mint a ciklussal megírt változat.

Mivel rekurziónál a régebben kiszámolt értékek lehet hogy nem elérhetőek, ezért a gondtalanul megírt rekurzív kód lehet hogy fölöslegesen sokat számol. Példának itt van ez a rosszul megírt változata a fibonacci számok kiszámolásának:

link

Végigléptetve, a fibonacci_rekurziv(3) meg van hívva a 11-es és a 34-es lépésnél is, és mindkétszer újra ki van számolva. A matematikai gondolkodásmód szerint ugyan igaz hogy mindkét esetben a 3. fibonacci szám értékére van szükség, de programozásnál azt is végig kell gondolni hogy ez milyen lépésekkel fog járni.

Összességében a ciklus mindenképp könnyebben használható ha:

  • sok változóra van szükség a kód belsejében
  • egy táblázatot töltünk fel
  • a ciklus sok egymástól független elemmel dolgozik

Olyan esetben is érdemesebb ciklust használni mint rekurziót, amikor a rekurzió mélysége (hány példánya fut a függvénynek egyszerre) nagyon megnőhetne, mert az a hatékonyságot csökkenti nagy memóriaigényével.

Rekurzió előnyei

Tekintsük a következő feladatot:

Egy k szám osztósora egy olyan pozitív egészekből álló számsor, ami k-val kezdődik, 1-el végződik, és a következő szám mindig az előző osztója. Pl. a 24, 12, 3, 1 az a 24 egy osztósora. Írjunk egy függvényt ami kiírja egy szám összes osztósorát.

Egy lehetséges megoldás rekurzióval:

link

Próbáljuk meg ugyanezt a megoldást reprodukálni ciklussal. Itt egy ilyen megoldás:

link

Ez a legegyszerűbb kód amit sikerült írnom, és még így is a kommentekkel együtt sem vagyok benne teljesen biztos hogy jól érthető. Itt van kommentek nélkül is, hogy látható legyen hogy mennyivel hosszabb és bonyolultabb:

def osztosor_ciklus(k):
    l = [k, 1]
    while 1:
        print l
        while len(l) > 1:
            l[-1] = l[-1] + 1
            if l[-1] == l[-2]:
                del l[-1]
            elif l[-2] % l[-1] == 0:
                l.append(1)
                break
        else:
            return

Ez egy olyan feladat, amire a rekurzió alkalmasabb. Amikor ciklussal csináljuk meg ugyanazt, akkor is vigyáznunk kell, hogy a lista hányadik eleménél éppen hol tartunk, mikor kell előre illetve visszalépnünk a listában. Ezek a rekurzív változatban a függvény hívásának és visszatérésének felelnek meg, így bizonyos mértékig "automatikusan" vannak kezelve.

De amit igazán fontos megérteni, hogy továbbra is a ciklusos kód a hatékonyabb. A rekurzív kód ugyan rövidebb, és a Python Tutor szerint kevesebb lépésből áll, de:

  • Egyszerre a félig kész listának több másolata létezik a függvény több futó példányában.
  • Maga a függvény több egyszerre futó példánya is memóriát fogyaszt, csökkenti a hatékonyságot.

Azonban ebben az esetben ez a felesleges munka nem lesz sokszorosa a szükséges munkának nagyobb esetekre se. Például úgyis a lista minden példányát ki kellett írni, azoknak mind létezni kell a függvény futása után, tehát az hogy menet közben több példány is létezik, az nem sokszorozza a memória igényt.

Viszont, a rekurzív kód könnyebben olvasható, és a működése könnyebben megérthető. Ez nem elvetendő szempont, mindenki a programozóként dolgozik, több időt tölt kód olvasásával, mint írásával.

Milyen esetben érdemes tehát rekurziót használni? Amikor érthetőbb kódot ad, és a hatékonyság vesztés nem jelentős, vagy nem számít. Néhány példa:

  • Gráfok bejárása.
  • Más olyan feladat, ahol a rekurzív változat egy ciklusban hívja önmagát.
  • Olyan táblázatok kitöltése, ahol a táblázatnak végül csak néhány eleme számít. Ilyenkor úgynevezett letárolásos rekurziót használunk.
  • Olyan problémáknál, ahol a kimenet maga rekurzív jellegű. Ilyen példa az osztósoros feladat, vagy fraktálok kirajzolása, különféle természetes folyamatok szimulációja.

Nézünk majd példákat a gyakorlaton.

Mutable és Immutable típusok

A pythonban két fajta változó van, mutable (kb. "változtatható"), és immutable (kb. "nem változtatható"). (Inkább az angol neveket használom, mert annak hogy nem változtatható változó nincs értelme, legalábbis nem az, amit igazából jelent az immutable.)

Immutable

Az immutable változó az egyszerűbb eset, ez az olyan változó, amiben bízhatunk, hogy csak akkor változik az értéke, ha mi értéket adunk neki:

link

Itt az látható, hogy ugyan azt mondtuk, hogy "b = a", amikor utána megváltoztatjuk a b értékét, annak nincs hatása az a értékére.

Ilyen fajta, tehát immutable, például a:

  • minden féle szám, tehát egész, valós (float) vagy akár komplex
  • igaz/hamis (boolean) változók
  • karakterláncok
  • tuple

Mutable

Kicsit nehezebb eset a mutable változók. Először nézzünk példa kódot

link

Itt azt láthatjuk, hogy amikor megváltoztatjuk a jojatekok értékét, akkor a jatekok értéke is megváltozik. Ez azért van, mert ugyan jatekok és jojatekok két külön változó, de ugyanarra a listára hivatkoznak. Ezt a python tutor is jelzi a fenti kódábrázolásban, azzal hogy nem a változó neve mellett van a lista tartalma, hanem onnan mutat egy nyíl a listára, és ott látható a tartalom.

Néhány változótípus, ami mutable:

  • Lista
  • Szótár
  • Halmaz
  • Általában minden bonyolultabb dolog.

Problémák

Miért fontos ez számunkra? Profibb felhasználók számára van amikor ezt jól ki tudják használni, hogy hatékony legyen a kódjuk. Azonban a jelenlegi szinten nekünk ez több problémát okoz, mint amiben segít. Ezért most arra koncentrálok, hogy hogyan tudjuk elkerülni hogy módosítsunk valamit amit nem akarunk. Egy példa:

link

Ha csak az utolsó 4 sort olvassuk el, teljesen logikusnak tűnik a dolog, de mégsem működik, mert a függvényen belül megváltoztattuk a listát amit kaptunk. Általános megoldás amit javaslok, függvényen belül soha ne változtassunk meg olyan mutable változókat amiket paraméterként kaptunk. Ha úgy egyszerű a kódunk hogy az eredeti listából/szótárból törlünk vagy módosítunk, akkor először készítsünk egy másolatot. Például az előző kódunk javított változata így nézhet ki:

link

Lista másolásához ez a [:] jelzés általános módszer a másoláshoz, a szótárnak van egy külön copy() metódusa, amit így lehet használni:

szotar = {"cica" : "kitten", "kutya" : "dog"}
szotar_masolat = szotar.copy()

Egyelőre ennyit elég tudni a mutable típusokról, még a félév folyamán később visszatérünk rájuk.

Személyes eszközök