{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## [Kivételkezelés](https://docs.python.org/3/tutorial/errors.html)\n", "\n", "- A kivételkezelés egy modern megközelítés a hibakezelésre. Lehetővé teszi hogy a legalkalmasabb helyen végezzük el a hibakezelést.\n", "- A korábban uralkodó a hibakód alapú nehézkesebb. Tegyük fel, hogy a függvényhívási stack sokadik szintjén lép fel egy hiba. A hibát a kód sok pontján kell kezelni (a hívó függvényben, a hívót hívó függvényben stb.), ami kódduplikáláshoz vagy GOTO utasítások alkalmazásához vezet.\n", "- A kivételeket a [raise](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) utasítás segítségével lehet létrehozni, és a [try](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement) utasítás segítségével lehet elkapni.\n", "- A beépített kivétel típusok hierarchiája [itt](https://docs.python.org/3/library/exceptions.html#exception-hierarchy) tekinthető át." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Kérek egy páros számot: 11\n" ] }, { "ename": "ValueError", "evalue": "n páratlan", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[1], line 4\u001b[0m\n\u001b[0;32m 2\u001b[0m n \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mint\u001b[39m(\u001b[38;5;28minput\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mKérek egy páros számot: \u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[0;32m 3\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m n \u001b[38;5;241m%\u001b[39m \u001b[38;5;241m2\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m----> 4\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mn páratlan\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m 5\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mVÉGE\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", "\u001b[1;31mValueError\u001b[0m: n páratlan" ] } ], "source": [ "# Kivétel létrehozása.\n", "n = int(input('Kérek egy páros számot: '))\n", "if n % 2 == 1:\n", " raise ValueError('n páratlan')\n", "print('VÉGE')" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x: asd\n", "ValueError\n", "FOO\n", "VÉGE\n" ] } ], "source": [ "# Kivétel elkapása.\n", "try:\n", " x = float(input('x: '))\n", " y = float(input('y: '))\n", " print(x / y)\n", "except ValueError:\n", " print('ValueError')\n", "except ZeroDivisionError:\n", " print('ZeroDivisionError')\n", "finally:\n", " print('FOO')\n", " \n", "print('VÉGE')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hibakeresés" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "ename": "ZeroDivisionError", "evalue": "division by zero", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[3], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# Első lépés: A hibaüzenetet MINDIG olvassuk el! :-)\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;241m1\u001b[39m \u001b[38;5;241m/\u001b[39m \u001b[38;5;241m0\u001b[39m\n", "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" ] } ], "source": [ "# Első lépés: A hibaüzenetet MINDIG olvassuk el! :-)\n", "1 / 0" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# Példa egy hibás függvényre.\n", "def calc_average(list_of_lists):\n", " joined = []\n", " for l in list_of_lists:\n", " joined.append(l)\n", " return sum(joined) / len(joined)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for +: 'int' and 'list'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[5], line 3\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;66;03m# Számítsuk ki az alábbi számok átlagát!\u001b[39;00m\n\u001b[0;32m 2\u001b[0m sequences \u001b[38;5;241m=\u001b[39m [[\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m, \u001b[38;5;241m3\u001b[39m], [\u001b[38;5;241m4\u001b[39m, \u001b[38;5;241m5\u001b[39m], [\u001b[38;5;241m6\u001b[39m, \u001b[38;5;241m7\u001b[39m]]\n\u001b[1;32m----> 3\u001b[0m \u001b[38;5;28mprint\u001b[39m(calc_average(sequences))\n", "Cell \u001b[1;32mIn[4], line 6\u001b[0m, in \u001b[0;36mcalc_average\u001b[1;34m(list_of_lists)\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m l \u001b[38;5;129;01min\u001b[39;00m list_of_lists:\n\u001b[0;32m 5\u001b[0m joined\u001b[38;5;241m.\u001b[39mappend(l)\n\u001b[1;32m----> 6\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28msum\u001b[39m(joined) \u001b[38;5;241m/\u001b[39m \u001b[38;5;28mlen\u001b[39m(joined)\n", "\u001b[1;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'list'" ] } ], "source": [ "# Számítsuk ki az alábbi számok átlagát!\n", "sequences = [[1, 2, 3], [4, 5], [6, 7]]\n", "print(calc_average(sequences))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "> \u001b[1;32mc:\\users\\puszt\\appdata\\local\\temp\\ipykernel_20788\\261683529.py\u001b[0m(6)\u001b[0;36mcalc_average\u001b[1;34m()\u001b[0m\n", "\n", "ipdb> print(joined)\n", "[[1, 2, 3], [4, 5], [6, 7]]\n", "ipdb> q\n" ] } ], "source": [ "# Keressük meg a hibát a %debug parancs segítségével!\n", "%debug" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4.0\n" ] } ], "source": [ "# A függvény javított változata.\n", "def calc_average(list_of_lists):\n", " joined = []\n", " for l in list_of_lists:\n", " joined.extend(l)\n", " return sum(joined) / len(joined)\n", "\n", "print(calc_average(sequences))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fejezetek a [standard könyvtárból](https://docs.python.org/3/library/index.html) II." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### [collections](https://docs.python.org/3/library/collections.html)\n", "- Specializált konténer adattípusokat tartalmaz." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "import collections" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Counter({'a': 5, 'b': 2, 'r': 2, 'k': 1, 'd': 1})" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gyakoriságszámító szótár (Counter).\n", "s = 'abrakadabra'\n", "collections.Counter(s)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[('the', 1145),\n", " ('and', 973),\n", " ('to', 736),\n", " ('of', 674),\n", " ('i', 565),\n", " ('you', 539),\n", " ('a', 534),\n", " ('my', 513),\n", " ('in', 431),\n", " ('it', 409),\n", " ('that', 381),\n", " ('ham', 358),\n", " ('is', 339),\n", " ('not', 310),\n", " ('his', 297),\n", " ('this', 297),\n", " ('with', 268),\n", " ('but', 258),\n", " ('for', 248),\n", " ('your', 241),\n", " ('me', 231),\n", " ('lord', 223),\n", " ('as', 219),\n", " ('be', 216),\n", " ('he', 213),\n", " ('what', 200),\n", " ('king', 195),\n", " ('him', 195),\n", " ('so', 194),\n", " ('have', 180)]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# A szavak gyakorisága a Hamletben, Counterrel kiszámolva.\n", "import collections, string\n", "words = open('hamlet.txt').read().lower().split()\n", "words = [w.strip(string.punctuation) for w in words]\n", "collections.Counter(words).most_common(30)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "# Alapértelmezett értékkel rendelkező szótár (defaultdict).\n", "d = collections.defaultdict(list)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "# Új kulcs-érték pár hozzáadása.\n", "d['aa'] = [1, 2, 3]" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d['aa']" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Hivatkozás nem létező kulcsra.\n", "# Nem fog hibát adni, hanem az alapértelmezett értéket rendeli a kulcshoz.\n", "# Az alapértelmezett érték a list() függvényhívással jön létre.\n", "d['bb']" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defaultdict(list, {'aa': [1, 2, 3], 'bb': []})" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# Hivatkozás nem létező kulcsra, majd egy elem hozzáfűzése.\n", "d['cc'].append(10)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defaultdict(list, {'aa': [1, 2, 3], 'bb': [], 'cc': [10]})" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'aa': [1, 2, 3], 'bb': [], 'cc': [10]}" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Hagyományos szótárrá konvertálás.\n", "d2 = dict(d)\n", "d2" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defaultdict(, {'asdf': {10, 20, 30}})" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Defaultdict egyedi default értékkel.\n", "def moricka():\n", " return {10, 20}\n", "\n", "d3 = collections.defaultdict(moricka)\n", "d3['asdf'].add(30)\n", "d3" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "defaultdict(()>, {'asdf': {10, 20, 30}})" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d3 = collections.defaultdict(lambda: {10, 20})\n", "d3['asdf'].add(30)\n", "d3" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "# Nevesített elemekkel rendelkező tuple (namedtuple).\n", "Game = collections.namedtuple('Game', ['round', 'hteam', 'ateam', 'hgoals', 'agoals'])" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Game(round=10, hteam='Liverpool', ateam='Arsenal', hgoals=1, agoals=2)" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Tuple stílusú használat.\n", "g = Game(10, 'Liverpool', 'Arsenal', 1, 2)\n", "g" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "g[0]" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Liverpool'" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Struktúra stílusú használat.\n", "g.hteam" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{Game(round=10, hteam='Liverpool', ateam='Arsenal', hgoals=1, agoals=2): 'alma'}" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# A namedtuple típus használható szótárkulcsként.\n", "{g: 'alma'}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### [copy](https://docs.python.org/3/library/copy.html)\n", "- Sekély (shallow) és mély (deep) másoló függvényt tartalmaz." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "import copy" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[100, 20, 30]" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Pythonban az értékadás NEM végez másolást, csak hivatkozást hoz létre.\n", "a = [10, 20, 30]\n", "b = a # <= NEM készül másolat!\n", "b[0] = 100\n", "a" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[10, 20, 30]\n", "[100, 20, 30]\n" ] } ], "source": [ "# Sekély másolat készítése.\n", "a = [10, 20, 30]\n", "b = copy.copy(a) # sekély másolat készítése\n", "b[0] = 100\n", "print(a)\n", "print(b)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[100], [20], [30]]\n", "[[100], [20], [30]]\n" ] } ], "source": [ "# Sekély másolat készítése egy listák listája objektumról.\n", "a = [[10], [20], [30]]\n", "b = copy.copy(a) # sekély másolat készítése\n", "b[0][0] = 100\n", "print(a)\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A copy.copy() csak az adatszerkezet legfelső szintjén végez másolást!" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[10], [20], [30]]\n", "[[100], [20], [30]]\n" ] } ], "source": [ "# Mély másolat készítése egy listák listája objektumról.\n", "a = [[10], [20], [30]]\n", "b = copy.deepcopy(a) # mély másolat készítése\n", "b[0][0] = 100\n", "print(a)\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### [glob](https://docs.python.org/3/library/glob.html)\n", "- Tartalmaz egy függvényt adott mintára illeszkedő fájlnevek összegyűjtésére." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "import glob" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['celsius_fahrenheit.txt',\n", " 'example_file.txt',\n", " 'example_file_2.txt',\n", " 'hamlet.txt',\n", " 'hotels.txt',\n", " 'igazi.txt',\n", " 'investments.txt',\n", " 'matrix.txt',\n", " 'openair.txt',\n", " 'pl.txt',\n", " 'unicef.txt']" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# .txt kiterjeszésű fájlok az aktuális könyvtárban.\n", "glob.glob('*.txt')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### [gzip](https://docs.python.org/3/library/gzip.html)\n", "\n", "- GZIP formátumú tömörített fájlok olvasására és írására biztosít eszközöket.\n", "- Megjegyzés: Egyéb tömörített formátumokat is támogat a standard könyvtár (pl. BZ2, LZMA, ZIP, TAR)." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "import gzip" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "200" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# GZIP formátumú fájl elkészítése.\n", "text = 'Móricka Pythonozik. ' * 10\n", "gzip.open('moricka.gz', 'wt').write(text)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Móricka Pythonozik. Móricka Pythonozik. Móricka Pythonozik. Móricka Pythonozik. Móricka Pythonozik. Móricka Pythonozik. Móricka Pythonozik. Móricka Pythonozik. Móricka Pythonozik. Móricka Pythonozik. '" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# GZIP formátumú fájl beolvasása.\n", "gzip.open('moricka.gz', 'rt').read()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### [os](https://docs.python.org/3/library/os.html)\n", "\n", "- Az operációs rendszer bizonyos szolgáltatásaihoz nyújt elérést." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "import os" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Létezik-e hamlet.txt nevű fájl az aktuális könyvtárban?\n", "os.path.exists('hamlet.txt')" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'/tmp/xyz'" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Könyvtárnév kinyerése egy elérési útvonalból.\n", "os.path.dirname('/tmp/xyz/hamlet.txt')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### [pickle](https://docs.python.org/3/library/pickle.html)\n", "\n", "- Python adatszerkezetek szerializálására (azaz bájtsorozattá alakítására) és deszerializálására nyújt egy megoldást.\n", "- A \"pickle\" szó jelentése főnévként \"ecetes lé\", \"pác\", igeként \"savanyítás\" :-)." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "import pickle" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "# Összetett objektum szerializálása fájlba.\n", "data = [10, 20, {'abc', 'de'}]\n", "pickle.dump(data, open('data.pkl', 'wb'))" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 20, {'abc', 'de'}]" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Deszerializálás.\n", "data2 = pickle.load(open('data.pkl', 'rb'))\n", "data2" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "b'\\x80\\x04\\x95\\x18\\x00\\x00\\x00\\x00\\x00\\x00\\x00]\\x94(K\\nK\\x14\\x8f\\x94(\\x8c\\x02de\\x94\\x8c\\x03abc\\x94\\x90e.'" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Szerializálás bájtsorozatba.\n", "data = [10, 20, {'abc', 'de'}]\n", "b = pickle.dumps(data)\n", "b" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 20, {'abc', 'de'}]" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Deszerializálás.\n", "pickle.loads(b)" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [], "source": [ "# Két hasznos segédfüggvény.\n", "\n", "def to_pickle(obj, fname, protocol=4):\n", " '''Serialize object to file.'''\n", " pickle.dump(obj, open(fname, 'wb'), protocol)\n", " \n", "def from_pickle(fname):\n", " '''Deserialize object from file.'''\n", " return pickle.load(open(fname, 'rb'))" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "to_pickle(data, 'data.pkl')" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 20, {'abc', 'de'}]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from_pickle('data.pkl')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.11.3" } }, "nbformat": 4, "nbformat_minor": 2 }