{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Algoritmusok Python nyelven\n", "\n", "## 5. Előadás: Iterátorok, generátorok.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sokféle objektumot tudunk használni for ciklusokban:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "3\n", "4\n" ] } ], "source": [ "for i in [1, 2, 3, 4]:\n", " print(i)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "p\n", "y\n", "t\n", "h\n", "o\n", "n\n" ] } ], "source": [ "for c in \"python\":\n", " print(c)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x\n", "y\n" ] } ], "source": [ "for k in {\"x\": 1, \"y\": 2}:\n", " print(k)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1,Donielle,Vickar,dvickar0@tmall.com,true\n", "\n", "2,Perle,Claye,pclaye1@blogs.com,true\n", "\n", "3,Flori,Wharf,fwharf2@zdnet.com,true\n", "\n", "4,Kristen,Haryngton,kharyngton3@yelp.com,false\n", "\n", "5,Bibby,Covill,bcovill4@psu.edu,true\n", "\n", "6,Illa,D'Elias,idelias5@twitter.com,true\n", "\n", "7,Genia,Woodyear,gwoodyear6@reuters.com,false\n", "\n", "8,Patrice,Rhys,prhys7@meetup.com,false\n", "\n", "9,Rich,Gavozzi,rgavozzi8@istockphoto.com,false\n", "\n", "10,Elfie,Comben,ecomben9@un.org,true\n" ] } ], "source": [ "with open(\"pelda_fajl.txt\", \"r\") as fajlobj:\n", " for line in fajlobj:\n", " print(line)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ezeket az osztályokat közösen **iterálható** osztályoknak hívjuk.\n", "Az iterálható osztályokhoz tartozik egy-egy **iterátor**, amit megkaphatunk az `iter` függvénnyel. A `next()` függvény megadja az iterátor következő elemét. Ha már nincs több elem, `StopIteration` hibát kapunk. (Emiatt egyszerhasználatosak az iterátorok.)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "S\n", "ü\n", "s\n", "ü\n" ] }, { "ename": "StopIteration", "evalue": "", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mStopIteration\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmyiter\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmyiter\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmyiter\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mStopIteration\u001b[0m: " ] } ], "source": [ "myiter=iter(\"Süsü\")\n", "print(next(myiter))\n", "print(next(myiter))\n", "print(next(myiter))\n", "print(next(myiter))\n", "print(next(myiter))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ez a két tulajdonság definiálja is az iterátorokat. Tehát egy iterátornak a következőket kell tudnia:\n", "1. Van egy `__next__` függvénye, ami visszadja sorban az elemeket és\n", "2. `StopIteration` hibát ad, ha nincs több elem.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Egy osztály **iterálható** ha a van egy `__iter__` függvénye ami visszatér egy **iterátorral**, aminek\n" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Aktuális: 4\n", "4\n", "Aktuális: 3\n", "3\n", "Aktuális: 2\n", "2\n", "Aktuális: 1\n", "1\n", "Aktuális: 0\n", "0\n" ] } ], "source": [ "class MyIterator:\n", " def __init__(self):\n", " self.iter_no = 5\n", " \n", " def __iter__(self):\n", " return self\n", " \n", " def __next__(self):\n", " if self.iter_no <= 0:\n", " raise StopIteration()\n", " self.iter_no = self.iter_no- 1\n", " print(\"Aktuális: {}\".format(self.iter_no))\n", " return self.iter_no\n", " #return \"itt tartunk:\"+str(self.iter_no)\n", " \n", "myiter = MyIterator()\n", "\n", "for i in myiter:\n", " print(i)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Süsü', 1]\n", "['Smaug', 1]\n", "['Hétfejű', 1]\n", "['Hétfejű', 2]\n", "['Hétfejű', 3]\n", "['Hétfejű', 4]\n", "['Hétfejű', 5]\n", "['Hétfejű', 6]\n", "['Hétfejű', 7]\n", "['Ghidorah', 1]\n", "['Ghidorah', 2]\n", "['Ghidorah', 3]\n" ] } ], "source": [ "class Sarkanyiterator:\n", " def __init__(self,fejlista):\n", " self.fejlista=fejlista\n", " self.aktualis_sarkany=0\n", " self.aktualis_fej=1\n", " \n", " \n", " def __next__(self):\n", " mostani_sarkany=self.aktualis_sarkany\n", " mostani_fej=self.aktualis_fej\n", " if self.aktualis_sarkany>=len(self.fejlista) or (self.aktualis_sarkany==len(self.fejlista)-1 and self.aktualis_fej>self.fejlista[-1][1]):\n", " raise StopIteration()\n", " \n", " if self.fejlista[self.aktualis_sarkany][1]>self.aktualis_fej:\n", " self.aktualis_fej= self.aktualis_fej+1\n", " else:\n", " self.aktualis_sarkany=self.aktualis_sarkany+1\n", " self.aktualis_fej=1\n", " \n", " return [self.fejlista[ mostani_sarkany][0],mostani_fej]\n", " \n", " \n", "class SarkanyBarlang:\n", " def __init__(self):\n", " self.sarkanyfejlista = [(\"Süsü\",1),(\"Smaug\",1),(\"Hétfejű\",7),(\"Ghidorah\",3)]\n", " \n", " def __iter__(self):\n", " return Sarkanyiterator(self.sarkanyfejlista)\n", " \n", "barlang = SarkanyBarlang()\n", "\n", "for fej in barlang:\n", " print(fej)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Rengeteg függvény van, ami elfogad bármilyen iterátort!** " ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['Süsü', 1],\n", " ['Smaug', 1],\n", " ['Hétfejű', 1],\n", " ['Hétfejű', 2],\n", " ['Hétfejű', 3],\n", " ['Hétfejű', 4],\n", " ['Hétfejű', 5],\n", " ['Hétfejű', 6],\n", " ['Hétfejű', 7],\n", " ['Ghidorah', 1],\n", " ['Ghidorah', 2],\n", " ['Ghidorah', 3]]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(barlang)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Hétfejű', 7]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "max(barlang,key=lambda x:x[1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Iterátorok gyártása gyorsabban\n", "### Generátor kifejezések\n", "\n", "A **generátorok** speciális iterátorok. A fő gondolat mögöttük, hogy sokszor nincs szükség egy list összes elemének a legyártásához, ha csak végig akarunk haladni a listán, hanem elég, ha mindig ki tudjuk számítani a következő elemet. Így sokkal kevesebb memóriát használ a gép. \n", "\n", "Több mód is van a generátorok létrehozására, az egyik a **generátor kifejezések**, amik a list comprehensionök általánosításai. \n", "\n", "Egy generátor kifejezést megadhatunk úgy, hogy () zárójelek közé írjuk a list comprehension kódját a [] zárójelek helyett. " ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9999999900000000\n" ] } ], "source": [ "N = 8\n", "s = sum([i*2 for i in range(int(10**N))])\n", "print(s)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9999999900000000\n" ] } ], "source": [ "s = sum((i*2 for i in range(int(10**N))))\n", "print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mivel a generátorok csak végéghaladnak a listán és nem gyártják azt le, így ezek is csak egyszerhasználatosak." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ " at 0x000002AB2BCCB148>" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "even_numbers = (2*n for n in range(10))\n", "even_numbers" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "2\n", "4\n", "6\n", "8\n", "10\n", "12\n", "14\n", "16\n", "18\n" ] } ], "source": [ "for num in even_numbers:\n", " print(num)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Második futásra már üres:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "for num in even_numbers:\n", " print(num)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Minden generátor objektum is egyben iterátor, tehát a `next()` függvény megadja a következő elemet, ha pedig már nincs, `StopIteration` hibát ad. " ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "2\n", "4\n", "6\n", "8\n", "10\n", "12\n", "14\n", "16\n", "18\n" ] } ], "source": [ "even_numbers = (2*n for n in range(10))\n", "\n", "while True:\n", " try:\n", " print(next(even_numbers))\n", " except StopIteration:\n", " break" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "ename": "StopIteration", "evalue": "", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mStopIteration\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0meven_numbers\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# StopIteration\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mStopIteration\u001b[0m: " ] } ], "source": [ " next(even_numbers) # StopIteration" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `yield` kulcsszó\n", "\n", "Egy másik mód generátork gyártására, a **generátor függvények**.\n", "- Ehhez olyan függvényt kell írni, ahol `yield` kulcsszót használunk értékek visszaadására. \n", "- A függvény egy olyan generátort hoz létre, ami mindig a következő `yield` parancsig futtatja a függvényt, és így kapja meg a következő értéket. Tehát a next() hatására a függvény addig fut, amíg el nem ér egy `yield` parancsig, vagy ha véget ér a függvény `yield` nélkül, akkor egy `StopIteration` kivételt dob." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "def magyar_maganhangzok():\n", " alphabet = (\"a\", \"á\", \"e\", \"é\", \"i\", \"í\", \"o\", \"ó\",\n", " \"ö\", \"ő\", \"u\", \"ú\", \"ü\", \"ű\")\n", " for maganhangzo in alphabet:\n", " yield maganhangzo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ez a függvény egy **generátor objektummal** tér vissza." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "generator" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(magyar_maganhangzok())" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a\n", "á\n", "e\n", "é\n", "i\n", "í\n", "o\n", "ó\n", "ö\n", "ő\n", "u\n", "ú\n", "ü\n", "ű\n" ] } ], "source": [ "for vowel in magyar_maganhangzok():\n", " print(vowel)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A generátor függvény minden hívás esetén legyárt egy generátor objektumot:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "gen1 first time: ['a', 'á', 'e', 'é', 'i', 'í', 'o', 'ó', 'ö', 'ő', 'u', 'ú', 'ü', 'ű']\n", "gen1 second time: []\n", "gen2 first time: ['a', 'á', 'e', 'é', 'i', 'í', 'o', 'ó', 'ö', 'ő', 'u', 'ú', 'ü', 'ű']\n" ] } ], "source": [ "gen1 = magyar_maganhangzok()\n", "gen2 = magyar_maganhangzok()\n", "\n", "print(gen1 is gen2)\n", "print(\"gen1 first time:\", list(gen1))\n", "print(\"gen1 second time:\", list(gen1))\n", "print(\"gen2 first time:\", list(gen2))" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "def sarkanyfejek(fejlista):\n", " for sarkany in fejlista:\n", " for i in range(sarkany[1]):\n", " yield [sarkany[0],i+1]" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Süsü', 1]\n", "['Smaug', 1]\n", "['Hétfejű', 1]\n", "['Hétfejű', 2]\n", "['Hétfejű', 3]\n", "['Hétfejű', 4]\n", "['Hétfejű', 5]\n", "['Hétfejű', 6]\n", "['Hétfejű', 7]\n", "['Ghidorah', 1]\n", "['Ghidorah', 2]\n", "['Ghidorah', 3]\n" ] } ], "source": [ "barlang = SarkanyBarlang()\n", "fejiterator=sarkanyfejek(barlang.sarkanyfejlista)\n", "for fej in fejiterator:\n", " print(fej)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Süsü', 1]" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fejiterator=sarkanyfejek(barlang.sarkanyfejlista)\n", "max(fejiterator)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### itertools modul\n", "- az iterátorok akkor válnak igazán hasznossá, ha kibővítjük őke. \n", "- az itertools modulban rengeteg bővítés van iterátorokhoz, megéri elolvasni a hivatalos leírást: https://docs.python.org/3.8/library/itertools.html#module-itertools\n", "\n", "Néhány példa:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "import itertools as it" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Végtelen iterátorok:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A\n", "B\n", "C\n", "D\n", "A\n", "B\n", "C\n", "D\n", "A\n", "B\n" ] } ], "source": [ "gen=it.cycle('ABCD')\n", "for _ in range(10):\n", " print(next(gen))" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n", "4\n", "5\n", "6\n", "7\n", "8\n", "9\n", "10\n", "11\n", "12\n" ] } ], "source": [ "gen=it.count(3)\n", "for _ in range(10):\n", " print(next(gen))" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(filter(lambda x: x%2, range(10)))" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 2, 4, 6, 8]" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(it.filterfalse(lambda x: x%2, range(10)))" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A\n", "B\n", "C\n", "0\n", "1\n", "2\n", "3\n", "4\n", "5\n", "6\n", "7\n", "8\n", "9\n" ] } ], "source": [ "c=it.chain.from_iterable(['ABC', range(10)])\n", "for a in c:\n", " print(a)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 0\n", "0 1\n", "0 2\n", "0 3\n", "1 0\n", "1 1\n", "1 2\n", "1 3\n", "2 0\n", "2 1\n", "2 2\n", "2 3\n" ] } ], "source": [ "for i,j in it.product(range(3),range(4)):\n", " print(i,j)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### map\n", " a `map` meghívja a megadott függvényt az iterátor minden elemére" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[4, 6, 'abcabc']" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def double(e):\n", " return e + e\n", "\n", "l = [2, 3, \"abc\"]\n", "\n", "list(map(double, l))" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "m=map(double, l)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "ename": "StopIteration", "evalue": "", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mStopIteration\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mnext\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mm\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mStopIteration\u001b[0m: " ] } ], "source": [ "next(m)" ] }, { "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.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }