{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Függvényhívás\n",
"Mi történik függvényhíváskor? \n",
"\n",
"Emeljük négyzetre egy lista elemeit:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def square(L):\n",
" new_L = []\n",
" for i in L:\n",
" new_L.append(i*i)\n",
" return new_L\n",
"\n",
"numbers = [5, 1, 8]\n",
"sq_numbers = square(numbers)\n",
"\n",
"print(numbers)\n",
"print(sq_numbers)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Itt egyszerűen az [5, 1, 8]
lista elemeit emeljük négyzetre.\n",
"\n",
"Mi történik, ha közvetlenül a paraméterként kapott L
lista elemeit emeljük négyzetre?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def square(L):\n",
" for i in range(len(L)):\n",
" L[i] = L[i] * L[i]\n",
" return L\n",
"\n",
"numbers = [5, 1, 8]\n",
"sq_numbers = square(numbers)\n",
"\n",
"print(numbers)\n",
"print(sq_numbers)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Mitől változott meg így az argumentumként átadott `numbers` lista is? Nézzünk egy hasonló példát: egyetlen számot emeljünk négyzetre!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def square(n):\n",
" n = n * n\n",
" return n\n",
"\n",
"number = 5\n",
"sq_number = square(number)\n",
"\n",
"print(number)\n",
"print(sq_number)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Most miért nem változott meg az argumentumként adott `number`, mikor a függvényben megváltoztattuk a paraméter értékét?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Érték szerinti paraméterátadás\n",
"Pythonban (és sok más programnyelvben) egy függvény paraméterei **érték szerint** adódnak át.\n",
"\n",
"Ez azt jelenti, hogy egy függvény paraméterei nem egyeznek meg az argumentumként adott változókkal, hanem azok **másolatai** lesznek. Ezért nem változott meg az előző példában a `number` változó. Hasonló történik a lebegőpontos számokkal vagy logikai értékekkel is.\n",
"\n",
"A listák esetében is másolat adódik át, de a másolat nem a listáról készül, hanem a lista **memóriacíméről**.\n",
"\n",
"Összetett adatszerkezetek esetén, mint a lista, tuple, szótár, saját osztályok objektumai,... valójában a változó egy memóriacímet tárol, azt a címet ahol az objektum található a számítógép memóriájában.\n",
"\n",
"1. példa\n",
"\n",
"2. példa\n",
"\n",
"3. példa\n",
"\n",
"\n",
"Ezért amikor olyan függvényt írunk mely listát kap paraméterként, mindig érdemes előre tisztázni, hogy a függvény megváltoztatja-e a lista elemeit vagy nem."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Listák másolása (kitérő)\n",
"\n",
"Számok (vagy más egyszerű – primitív típusok) másolása úgy történik, ahogy arra számítunk, vagyis az értékük másolódik:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"x = 5\n",
"y = x\n",
"y = 111\n",
"\n",
"print(x, y)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"pythontutor"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ha listát elemenként akarunk másolni, akkor azt nem tehetjük meg egy egyenlőségjellel.\n",
"Ahhoz, hogy a lista elemei is lemásolódjanak, mást kell csinálnunk."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L1 = [1, 5, 2]\n",
"L2 = L1\n",
"L2.sort()\n",
"\n",
"print(L1)\n",
"print(L2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ebben a példában L1
és L2
is ugyanarra az objektumra, egy listára mutat: lásd a\n",
"pythontutorban."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = [1,2,3]\n",
"M = L[:] #<<<<<<\n",
"M[1] = 9\n",
"print(L)\n",
"print(M)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Még bonyolultab a helyzet a tömbbel (listák listájával)!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"M1 = [[1, 2], [3, 4]]\n",
"M2 = M1[:]\n",
"M3 = M1[:]\n",
"\n",
"M2[0] = [55, 22]\n",
"M3[0][0] = 555\n",
"\n",
"print(M1)\n",
"print(M2)\n",
"print(M3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Mi is történik most? (lásd a\n",
"pythontutorban)\n",
"\n",
"Látható, a részlistás másolással az külső lista lemásolódott, de a belsők még mindig ugyanazok.\n",
"\n",
"Hogyan másoljunk biztosan akármilyen mélységig listát:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import copy\n",
"\n",
"M1 = [[1, 2], [3, 4]]\n",
"M2 = copy.deepcopy(M1)\n",
"M3 = copy.deepcopy(M1)\n",
"\n",
"M2[0] = [55, 22]\n",
"M3[0][0] = 555\n",
"\n",
"print(M1)\n",
"print(M2)\n",
"print(M3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A copy
csomag a másolásra hasznos függvényeket tartalmazza, a deepcopy
függvény jól lemásol egy listát, akármilyen mély legyen."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jegyezzük meg, hogy a hivatkozás megváltoztatása nem változtatja meg a hivatkozott objektumot. Törölhetjük-e egy lista elemeit a következő kóddal?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def erase(L):\n",
" L = []\n",
" \n",
"L = [1,2,5]\n",
"erase(L)\n",
"print(L)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = [1,2,5]\n",
"del L[:]\n",
"print(L)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"És ne feledkezzünk meg az _immutable_ objektumokról (pl. tuple, sztring), amelyek elemei egyáltalán nem változtathatók."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Extra függvény paraméterek\n",
"\n",
"### Opcionális változó\n",
"Megtörténhet, hogy egy függvénynek nem mindig akarjuk megadni az egyik paraméterét, mert pl. legtöbbször ugyanazzal az értékkel használnánk. A következő programban diákok Neptun-kódja és vizsgaeredménye alapján egy listába gyűjtjük azok kódját, akik átmentek a vizsgán:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def atmentek(hallgatok, ponthatar):\n",
" atment = []\n",
" for hallgato in hallgatok:\n",
" if hallgatok[hallgato] >= ponthatar:\n",
" atment.append(hallgato)\n",
" return atment\n",
"\n",
"hallgatok = {'RABCA8': 50, 'BATMAN': 23, '123ABC': 67}\n",
"print(atmentek(hallgatok, 40))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ekkor csinálhatjuk a következőt:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def atmentek(hallgatok, ponthatar=40):\n",
" atment = []\n",
" for hallgato in hallgatok:\n",
" if hallgatok[hallgato] >= ponthatar:\n",
" atment.append(hallgato)\n",
" return atment\n",
"\n",
"hallgatok = {'RABCA8': 50, 'BATMAN': 23, '123ABC': 67}\n",
"print(atmentek(hallgatok))\n",
"print(atmentek(hallgatok, 60))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nem csak egy opcionális paraméter adható meg, de azok csak a nem-opcionálisak után következhetnek:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def atmentek(hallgatok, ponthatar=40, sorban=True):\n",
" atment = []\n",
" for hallgato in hallgatok:\n",
" if hallgatok[hallgato] >= ponthatar:\n",
" atment.append(hallgato)\n",
" if sorban:\n",
" return sorted(atment)\n",
" else:\n",
" return atment\n",
"\n",
"hallgatok = {'RABCA8': 50, 'BATMAN': 23, '123ABC': 67}\n",
"print(atmentek(hallgatok, 40))\n",
"print(atmentek(hallgatok, 40, False))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Mi történik a következő függvényhívásnál?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(atmentek(hallgatok, False))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Az argumentumok sorrendje fontos! Itt a `ponthatar=False, sorban=True` értékek adódtak át, a `ponthatár=False` pedig azonos a `ponthatár=0` paraméterrel. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Nevesített paraméterek\n",
"\n",
"Lehet nevükkel hivatkozni az opcionális paramétereket! Ekkor sorrendjük nem számít, de azt a nevet kell írni az =
bal oldalára, ami a függvény definíciójában szerepel!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(atmentek(hallgatok, sorban=False))\n",
"print(atmentek(hallgatok, sorban=False, ponthatar=40))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"A P({x}, {y}) pontban\".format(y=3, x=4))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Változó számú argumentum\n",
"\n",
"Írjunk egy olyan függvényt, mely számok szorzatához hozzáad még egy adott konstanst!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def product(c, L):\n",
" szorzat = 1\n",
" for i in L:\n",
" szorzat *= i\n",
" return szorzat + c\n",
"\n",
"print(product(1, [1,2,3]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Mi lenne ha a szorzat tényezői is paraméterek lennének, nem pedig egy lista elemei?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def product2(c=0, x=1, y=1, z=1):\n",
" return x*y*z + c\n",
"\n",
"print(product2())\n",
"print(product2(1))\n",
"print(product2(1, 1))\n",
"print(product2(1, 1, 2))\n",
"print(product2(3, 1, 2, 3))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ez sajnos nem működik több változóra, csak ha kézzel hozzáfűzünk egy csomó opcionális paramétert.\n",
"\n",
"Ehelyett van a [variadikus](https://en.wikipedia.org/wiki/Variadic_function), vagy **váltózó számú paraméter**rel rendelkező függvény!\n",
"\n",
"Figyeljük meg, hogy az egyetlen különbség az eredeti product
függvényhez képest a *
"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def product3(c=0, *szamok):\n",
" szorzat = 1\n",
" for i in szamok:\n",
" szorzat *= i\n",
" return szorzat + c\n",
"\n",
"print(product3())\n",
"print(product3(5, 1, 2, 3, 4, 5, 6))\n",
"print(product3(5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ekkor a beírt paramétereket egy tuple-ben kapja meg a függvényünk. Ez lehet 0, 1 vagy több elemű is, de _iterálható_."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def variadic(*x):\n",
" return type(x)\n",
"\n",
"print(variadic(3,2))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Variadikus függvény meghívása\n",
"Mi van ha egy variadikus függvényt akarunk megívni, de az argumenumok már egy listában vannak?\n",
"\n",
"Ekkor ez nem jó:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"c = 5\n",
"L = [1, 2, 3]\n",
"print(product3(c, L))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Jó\n",
"print(product3(c, *L))\n",
"\n",
"# ez ekvivalens ezzel de bárhány elemmel működik:\n",
"print(product3(c, L[0], L[1], L[2]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Tetszőleges számú nevesített argumentumok: **kwargs\n",
"Írjunk függvényt, mely kiírja egy tudományos cikk megadott könyvtári adatait:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def article(**journal):\n",
" for i in journal:\n",
" print(i, \"=\", journal[i], end=\", \")\n",
" print()\n",
" \n",
"article(author=\"Endre Szemerédi\", title=\"On Sets of Integers Containing...\", year=1975)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Itt az argumentumok egy **könyvtárba** másolódnak, és eszerint kezelhetők."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def article(**journal):\n",
" print(type(journal))\n",
" \n",
"article(author=\"Euler\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Láthatóság\n",
"scope\n",
"\n",
"Hívhatunk azonos névvel kölünböző változókat, de a programnak tudnia kell, mikor melyiket kell használnia, honnan melyik **látható**!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def fuggveny(L):\n",
" # ez egy másik i\n",
" for i in L:\n",
" if i != 0:\n",
" return True\n",
" return False\n",
"\n",
"i = [0, 1, -1]\n",
"print(fuggveny(i))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def valami(L):\n",
" i = 10\n",
" for i in L:\n",
" i = 5*i\n",
" return i\n",
"\n",
"print(valami([1, 2, 3]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def valami2(L):\n",
" # lokális i\n",
" i = 0\n",
" for j in L:\n",
" i = i+j\n",
" return i\n",
"\n",
"# globális i\n",
"i = 10\n",
"print(valami2([1, 2, 3]))\n",
"print(i)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ha egy változót egy **függvény belsejében** hozunk létre (neve **lokális változó**), akkor ott az fog látszódni, akkor is, ha volt olyan nevű változónk máshol. Ez a változó megszűnik létezni, amikor a függvény befejezi futását (a `return után`) és nem változtatja az esetlegesen meglévő ugyanolyan nevű másutt használt változónkat.\n",
"\n",
"Sőt a függvény többszöri meghívásával újra létrejön, nem jegyzi meg értékét a függvényhívások között."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ha egy változót nem függvényben hozunk létre, akkor az minden más helyen látszódni fog (neve **globális változó**). A függvények belsejében is, hacsak nem hozunk létre ott lokális változót azonos névvel."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def f(x):\n",
" # az i itt globális\n",
" print(i)\n",
" \n",
"i = 10\n",
"f(None)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def f(x):\n",
" i = 0 # az i itt lokális\n",
" print(i)\n",
" \n",
"i = 10\n",
"f(None)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Elágazásnál (if
) figyeljünk, hogy a változónak ugyan nem mindig adunk értéket ha olyan ágban szerepel, de ettől még ott látható, így a másutt definiált azonos nevű változó itt nem fog látszani:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def f(x):\n",
" if x:\n",
" i = 0\n",
" return i\n",
" \n",
"i = 10\n",
"print(f(True))\n",
"print(f(False))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Függvény referencia\n",
"\n",
"Ha már ismerjük a referencia fogalmát, akkor egyszerűen adódik, hogy a függvények is csak referenciák, így használhatók akár függvény argumentumként is. Emlékezzünk előbb vissza a buborék rendezés algoritmusra:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def rendez(lista):\n",
" rendezve = lista[:]\n",
" for i in range(len(lista) - 1):\n",
" for j in range(len(lista) - i - 1):\n",
" if rendezve[j] > rendezve[j + 1]:\n",
" rendezve[j],rendezve[j+1] = rendezve[j+1],rendezve[j]\n",
" return rendezve\n",
"\n",
"L = [1, 8, 5, 2, 9, 3, 6]\n",
"\n",
"print(rendez(L))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Módosítsuk ezt úgy, hogy bármilyen rendezésre működjön! Írjunk először rendező függvényeket:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def novekvo(a, b):\n",
" if a < b:\n",
" return False\n",
" else:\n",
" return True\n",
" \n",
"def csokkeno(a, b):\n",
" if a > b:\n",
" return False\n",
" else:\n",
" return True"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"És adjunk a függvénynek egy alapértelmezett rendezést!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def rendez(lista, hasonlit=novekvo):\n",
" rendezve = lista[:]\n",
" for i in range(len(lista) - 1):\n",
" for j in range(len(lista) - i - 1):\n",
" if hasonlit(rendezve[j], rendezve[j + 1]):\n",
" rendezve[j],rendezve[j+1] = rendezve[j+1],rendezve[j]\n",
" return rendezve"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = [1, 8, 5, 2, 9, 3, 6]\n",
"\n",
"print(rendez(L))\n",
"print(rendez(L, csokkeno))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"type(novekvo)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
},
"pygments_lexer": "ipython3",
"version": "3.6"
},
"nbformat": 4,
"nbformat_minor": 1
}