{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "V této lekci se nučíte používat Pythonovské kontejnery: \n", "* [`tuple`](https://docs.python.org/2/library/functions.html#tuple) (neměnný seznam), \n", "* [`list`](https://docs.python.org/2/library/functions.html#list) (měnitelný seznam), \n", "* [`dict`](https://docs.python.org/2/library/stdtypes.html#dict) (asociativní pole),\n", "* [`set`](https://docs.python.org/2/library/stdtypes.html#set) (množina).\n", "\n", "Zjistíte, že:\n", "* Prvky nemusejí být stejného typu (nejsou homogenní).\n", "* Kontejnery mají v Pythonu zásadní význam a najdete je téměř všude.\n", "* Si nedokážete představit, jak může někdo programovat bez `list`, `tuple` nebo `dict`.\n", "* Pro indexování (při získávání i přiřazování prvku) se používají hranaté závorky []. Podobně jako v jazyce C se prvky indexují od 0.\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Poznámka na začátek: mutable versus immutable\n", "Datové typy mohou být *mutable* (měnitelný) nebo *immutable* (neměnitelný). Immutable objekty (v Pythonu je v podstatě všechno objekt -- mnohokrát se s tím ještě setkáme) nemoho měnit svou hodnotu. Naproti tomu mutable objekty svou hodnotu měnit mohou (aniž by ztratili svou identitu). Immutable typy jsou např čísla (`int`, `float`, `complex` atd.), řetězce (`str` a `unicode`) a `tuple`. Mutable typy jsou např. `list`, `dict` nebo `set`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tuple\n", "\n", "Správně česky snad \"n-tice\", nicméně často se používá prostě \"tuple\"." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tuple1=(1, 'a', 5)\n", "tuple2=(1, 'a')\n", "tuple3=('a', 'b')\n", "tuple4=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)\n", "tuple5=()\n", "tuple6=('single',)\n", "tuple7=(0, '1', (0, 1, 2))\n" ] } ], "source": [ "tuple1 = (1, 'a', 5) # Základní syntax vytváření tuple (kulaté závorky)\n", "tuple2 = 1, 'a' # Závorky nejsou povinné, ale... !\n", "tuple3 = tuple([\"a\", \"b\"]) # Pokročilé: Vytvoření tuple z jiného kontejneru\n", "tuple4 = tuple(range(0, 10)) # Pokročilé: Vytvoření tuple z iterátoru / generátoru\n", "tuple5 = () # Prázdný tuple\n", "tuple6 = (\"single\", ) # Tuple s jedním prvkem\n", "tuple7 = 0, \"1\", (0, 1, 2) # Tuple může pochopitelně obsahovat další tuple\n", "\n", "# A co nám vylezlo?\n", "print(f\"tuple1={tuple1}\")\n", "print(f\"tuple2={tuple2}\")\n", "print(f\"tuple3={tuple3}\")\n", "print(f\"tuple4={tuple4}\")\n", "print(f\"tuple5={tuple5}\")\n", "print(f\"tuple6={tuple6}\")\n", "print(f\"tuple7={tuple7}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "K získání prvku tuple použijeme hranaté závorky:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "9\n", "8\n" ] } ], "source": [ "print(tuple4[0]) # První prvek\n", "print(tuple4[-1]) # Poslední prvek\n", "print(tuple4[-2]) # Předposlední prvek" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tuple nelze měnit:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'tuple' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[3], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mtuple1\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mb\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;66;03m# Vyhodí výjimku\u001b[39;00m\n", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } ], "source": [ "tuple1[0] = \"b\" # Vyhodí výjimku" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lze ale vytvořit nový tuple z existujících" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(1, 'a', 5, 1, 'a')\n", "('single', 'single')\n" ] } ], "source": [ "print(tuple1 + tuple2)\n", "print(2 * tuple6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Metody tuple:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'count, index'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# I tuhle krkolomnou syntaxi brzy pochopíte ;-)\n", "\", \".join(item for item in dir(tuple) if not item.startswith(\"_\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Rozbalování (unpacking)\n", "Tuple lze použít pro přiřazení hodnot do více proměnných najednou. Např." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n" ] } ], "source": [ "(x, y, z) = (1, 2, 3)\n", "print(y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "V tomto případě se závorky často vynechávají, takže můžeme psát" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n" ] } ], "source": [ "x, y, z = (1, 2, 3)\n", "print(y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To je užitečné zejména pro funkce, které vracejí více hodnot." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "from math import ceil, floor\n", "\n", "def neighbors(x):\n", " \"\"\"Vrátí celá čísla a, b menší a větší než x, tj a < x < b\"\"\"\n", " a = int(floor(x))\n", " b = int(ceil(x))\n", " # pokud je x celé číslo, musíme přičíst/odečíst 1\n", " if a == x:\n", " a -= 1\n", " b += 1\n", " return a, b" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(-2, 0)\n" ] } ], "source": [ "\n", "# uvidíme, že funkce vrací tuple\n", "print(neighbors(-1))" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3 < 3.3 < 4\n" ] } ], "source": [ "x = 3.3\n", "# teď přiřadíme výsledek do dvou proměnných\n", "a, b = neighbors(x)\n", "print(f\"{a} < {x} < {b}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Na pravé straně může být jakýkoli iterabilní objekt (o iterátorech více později), např. seznam (o tom se dozvíme za chvilku) nebo string." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 2 3\n" ] } ], "source": [ "# vezmeme prvky ze seznamu\n", "a, b, c = [1, 2, 3]\n", "print(a, b, c)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A B C\n" ] } ], "source": [ "# a nebo z textového řetězce\n", "a, b, c = \"ABC\"\n", "print(a, b, c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ještě více možností přináší [*extended unpacking*](https://www.python.org/dev/peps/pep-3132/) a [*additional unpacking generalizations*](https://peps.python.org/pep-0448)." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "[3, 4, 5, 6]\n" ] } ], "source": [ "# do c se přiřadí všechny zbývající prvky v podobě seznamu\n", "a, b, *c = (1, 2, 3, 4, 5, 6)\n", "print(a)\n", "print(b)\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Důležitá je samozřejmě ona hvězdička, která může být i uprostřed." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "[2, 3, 4, 5]\n", "6\n" ] } ], "source": [ "a, *b, c = (1, 2, 3, 4, 5, 6)\n", "print(a)\n", "print(b)\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unpacking se hojně využívá i pro definice nebo volání funkcí, které mají proměnný počet argumentů. Všimněte si, že unpacking pomocí `*` může použit oběma směry - jak při volání, tak při definici funkce." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a<->A<->Z\n" ] } ], "source": [ "def print_all(*items, sep=\"<->\"):\n", " print(sep.join(items))\n", "\n", "\n", "arguments = (\"a\", \"A\", \"Z\")\n", "print_all(*arguments)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a↵\n", "A↵\n", "Z\n" ] } ], "source": [ "print_all(\"a\", \"A\", \"Z\", sep=\"↵\\n\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python vyhodí vyjímku pokud není počet prvků stejný" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "too many values to unpack (expected 3)", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[17], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m a, b, c \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)\n", "\u001b[0;31mValueError\u001b[0m: too many values to unpack (expected 3)" ] } ], "source": [ "a, b, c = (1, 2, 3, 4, 5, 6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## List (seznam)\n", "\n", "\n", "List je obdobou tuple, je ovšem mutable, tj. můžeme měnit jeho prvky. Vytváří se hranatými závorkami nebo funkcí `list`." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 'b', 'c']\n", "[0, 0.0, '0.0']\n", "[1, 'a', 5]\n" ] } ], "source": [ "list(), [] # prázdný list\n", "list1 = [\"a\", \"b\", \"c\"] # list vytvoříme pomocí [...]\n", "list2 = [0, 0.0, \"0.0\"] # můžeme tam dát libovolné typy\n", "list3 = list(tuple1) # nebo list vytvořit z tuple\n", "\n", "print(list1)\n", "print(list2)\n", "print(list3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Metod obsahuje list více než tuple, což vyplývá z toho, že je mutable." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'append, clear, copy, count, extend, index, insert, pop, remove, reverse, sort'" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\", \".join(item for item in dir(list) if not item.startswith(\"_\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Přirozené pro seznam je přidávání na konec pomocí `append` a odebírání z konce pomocí `pop`:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 'b', 'c', 'd']\n", "['d', 'c', 'b', 'a']\n", "a\n", "['d', 'c', 'b']\n" ] } ], "source": [ "list1.append(\"d\") # přidání prvku\n", "print(list1) # list1 se změnil!\n", "list1.sort(reverse=True)\n", "print(list1)\n", "print(list1.pop()) # vyjme poslední prvek\n", "print(list1) # který je z původního listu vymazán" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Odebrat prvek můžeme i pomocí `remove`, tato metoda ale musí prvek nejprve vyhledat." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['c', 'b']\n" ] } ], "source": [ "list1.remove(\"d\") # odstranění prvku(ů)\n", "print(list1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pomocí vnořených seznamů lze vytvářet \"vícerozměrné\" seznamy." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11\n" ] } ], "source": [ "l = [[11, 12], [21, 22]] # \"vícerozměnrý\" list\n", "print(l[0][0]) # prvek [0,0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Všechny mutable typy (a tedy i list) v podstatě reference nebo, chcete-li, ukazatele (pointery). Na to musíme pamatovat, abychom nechtěně nepřepisovali obsah jiné proměnné." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3]\n" ] } ], "source": [ "a = [1, 2, 3]\n", "b = a # b je identický list jako a (ne jeho kopie)\n", "b.insert(0, 0) # protože list je mutable, zmení se b i a\n", "print(a)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "print(a is b) # operátor is testuje identitu (objektů)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "True\n" ] } ], "source": [ "b = a.copy() # pokud chceme kopii, můžeme použít metodu copy\n", "\n", "print(a is b)\n", "print(a == b) # operátor == testuje hodnoty" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Jakmile `b` změníme, už se nezmění `a` jelikož jsme vytvořili nový objekt. Už se ani nerovnají podle hodnot, tj. podle operátoru `==`." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3]\n", "[0, 1, 2, 3, 5]\n", "False\n" ] } ], "source": [ "b.append(5)\n", "print(a)\n", "print(b)\n", "print(a == b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Indexování neboli řezání (*slicing*)\n", "Řezy jsou velice důležitým konceptem. Pro proměnný typu `list` a `tuple` lze řezy použít pro výběr prvku(ů) poměrně sofistikovaným způsobem, lze je použít i pro změnu seznamu. `list` a `tuple` umožňují tzv. jednoduchý řez (simple slice), detaily viz [dokumentace](http://docs.python.org/2/reference/expressions.html#slicings). Rozšířené řezy (extended slicing) uvidíme později pro pole Numpy. Syntaxe jednoduchého řezu je\n", "\n", " [[dolní_mez] : [horní_mez] [: [krok]]\n", " \n", "Implicitní hodnota pro horní a dolní mez je None, pro krok je implicitné hodnota 1. Výsledek obsahuje prveky s indexy od dolní meze (včetně) až po prvky s indexy menšími než horní mez, případně s daným krokem. Na příkladech si ukážeme, jak to funguje." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "# vytvoříme jednoduchý seznam (range v Pythonu 3 nevrací list, proto je lepší použít konverzi)\n", "l = list(range(10))\n", "# všechny prvky seznamu\n", "print(l[:])" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1]\n" ] } ], "source": [ "# První dva prvky\n", "print(l[0:2])" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[7, 8, 9]\n" ] } ], "source": [ "# Poslední tři prvky\n", "print(l[-3:])" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 2, 4, 6, 8]\n" ] } ], "source": [ "# Sudé prvky\n", "print(l[::2])" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n" ] } ], "source": [ "# obrácené pořadí pomocí řezů\n", "print(l[::-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pomocí řezů můžeme do seznamu prvky přidávat (pro přidávání existuje ještě metoda `insert`)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", "['jsem prvni', 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "l = list(range(10))\n", "print(l)\n", "l[:1] = [\"jsem prvni\"]\n", "print(l)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['jsem prvni', 'jedna', 'dva', 'tri', 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "# můžeme nahradit několik prvků jinými, jejichž počet nemusí být stejný\n", "l[1:3] = [\"jedna\", \"dva\", \"tri\"]\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... nebo je i mazat." ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", "[2, 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "l = list(range(10))\n", "print(l)\n", "# vymaže prvky [0:2]\n", "l[0:2] = []\n", "print(l)" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "# nebo můžeme použít del\n", "del l[0:2]\n", "print(l)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Už víme, že seznam (`list`) je *mutable* a že kopii můžeme vytvořit pomocí metody `copy`. Můžeme použít ale i řez [:], tj." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "a = [\"a\"]\n", "b = a[:]\n", "# otestujeme pomocí is, jestli jsou a, b identické obejkty\n", "print(a is b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Cvičení:** Vytvořte seznam programovacích jazyků (alespoň pěti), které znáte (nezapomeňte Python :). \n", "1. Pomocí metody `sort` ho setřiďte ho abecedy a vypište.\n", "2. Vypište první a poslední jazyk.\n", "3. Na konec seznamu přidejte jazyk \"Lisp\".\n", "4. Vymažte ze seznamu vše kromě prvních dvou a posledních dvou jazyků." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Hledání v seznamech\n", "Pro testování, zda je (není) prvek v seznamu (nebo tuple) použijeme klíčové slovo `in` (`not in`). Dále existuje metoda `index`, která vrací polohu nějakého prvku." ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "True\n" ] } ], "source": [ "l = [\"a\", \"A\", \"b\", \"ABC\", 1, \"2\"]\n", "# použijeme in pro test jestli list obsohuje \"b\" a \"B\"\n", "print(\"b\" in l)\n", "print(\"B\" in l)\n", "print(\"B\" not in l)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n" ] } ], "source": [ "# nyní vyzkoušíme metodu index\n", "print(l.index(\"b\"))" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "'B' is not in list", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[44], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43ml\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mindex\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mB\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m)\n", "\u001b[0;31mValueError\u001b[0m: 'B' is not in list" ] } ], "source": [ "print(l.index(\"B\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dictionary (slovník)\n", "\n", "Slovník je asociativní pole, jehož klíči jsou jakékoliv hashovatelné objekty (čísla, řetězce, tuply a většina uživatelsky definovatelných tříd). Jako klíč se nedají použít např. mutable kontejnery (`dict`, `list` apod.), které jsou nehashovatelné." ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{69: 5, 'pole_podle_skal': [1, 2, 3]}\n" ] } ], "source": [ "prazdny_slovnik = dict()\n", "prazdny_slovnik2 = {} # Ekvivalentní zápis\n", "\n", "slovnik = {69: 5, \"pole_podle_skal\" : [1, 2, 3]} # Různé typy uložených hodnot\n", "print(slovnik)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Získávání hodnot pomocí []" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n" ] } ], "source": [ "print(slovnik[69]) # => 5" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3]\n" ] } ], "source": [ "print(slovnik[\"pole_podle_skal\"]) # => [1, 2, 3]" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "ename": "KeyError", "evalue": "100", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[49], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mslovnik\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m100\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;66;03m# Neexistující klíč -> vyhodí výjimku\u001b[39;00m\n", "\u001b[0;31mKeyError\u001b[0m: 100" ] } ], "source": [ "slovnik[100] # Neexistující klíč -> vyhodí výjimku" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n", "vychozi_hodnota\n" ] } ], "source": [ "print(slovnik.get(100)) # Varianta, která výjimku nevyhodí (a vrátí None)\n", "print(slovnik.get(100, \"vychozi_hodnota\")) # Varianta, která vrátí definovanou výchozí hodnotu, když se prvek nenajde" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Metody slovníku:" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'clear, copy, fromkeys, get, items, keys, pop, popitem, setdefault, update, values'" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\", \".join(item for item in dir(dict) if not item.startswith(\"_\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pro test, zda slovník (ne)obsahuje položku s daným klíčem, slouží stejně jako pro tuple a list operátor `in`, resp. `not in`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Set (množina)\n", "\n", "Neřazený a neindexovatelný seznam hashovatelných prvků, ve kterém každý prvek smí být pouze jednou. V zásadě se chová podobně jako slovník obsahující jenom klíče.\n" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'krize', 'kule', 'piky', 'srdce'}\n", "{'a', 'b'}\n" ] } ], "source": [ "print({\"srdce\", \"piky\", \"kule\", \"krize\"})\n", "print(set((\"a\", \"a\", \"a\", \"b\", \"b\"))) # Duplicitní prvky se odstraní" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "<>:1: SyntaxWarning: 'set' object is not subscriptable; perhaps you missed a comma?\n", "<>:1: SyntaxWarning: 'set' object is not subscriptable; perhaps you missed a comma?\n", "/var/folders/dm/gbbql3p121z0tr22r2z98vy00000gn/T/ipykernel_39494/326244760.py:1: SyntaxWarning: 'set' object is not subscriptable; perhaps you missed a comma?\n", " {0}[0] # Nelze indexovat\n", "/var/folders/dm/gbbql3p121z0tr22r2z98vy00000gn/T/ipykernel_39494/326244760.py:1: SyntaxWarning: 'set' object is not subscriptable; perhaps you missed a comma?\n", " {0}[0] # Nelze indexovat\n", "/var/folders/dm/gbbql3p121z0tr22r2z98vy00000gn/T/ipykernel_39494/326244760.py:1: SyntaxWarning: 'set' object is not subscriptable; perhaps you missed a comma?\n", " {0}[0] # Nelze indexovat\n" ] }, { "ename": "TypeError", "evalue": "'set' object is not subscriptable", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[54], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43m{\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;66;03m# Nelze indexovat\u001b[39;00m\n", "\u001b[0;31mTypeError\u001b[0m: 'set' object is not subscriptable" ] } ], "source": [ "{0}[0] # Nelze indexovat" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pro množiny jsou k dispozici operátory (případně metody)\n", "\n", "* `|` (`union`)\n", "* `&` (`instersection`)\n", "* `-` (`difference`)\n", "* `^` (`symmetric_difference`)\n", "* `<`, `<=` (`issubset`)\n", "* `>`, `>=` (`issuperset`)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Cvičení:**:\n", "1. Vytvořte slovník ve kterém přiřadíte programovacím jazykům body podle oblíbenosti (1 - 10).\n", "2. Zjistěte pomocí množinových operací, které z vašich programovacích jazyků jsou a které nejsou společné s množinou `COMMON_LANGUAGES` definovanou níže." ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [], "source": [ "COMMON_LANGUAGES = {'Python', 'C', 'Java'}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vestavěné funkce pro práci s kontejnery\n", "Python má několik důležitých funkcí, které se hodí pro práci s kontejnery." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`len` vrací počet prvků" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "len([1, 1, 2, 2]) = 4\n" ] } ], "source": [ "o = [1, 1, 2, 2]\n", "len_o = len(o)\n", "print(f\"len({o}) = {len_o}\")" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "len({1, 2}) = 2\n" ] } ], "source": [ "o = {1, 1, 2, 2}\n", "len_o = len(o)\n", "print(f\"len({o}) = {len_o}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`sum` vrací součet prvků" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sum([1, 1, 2, 2]) = 6\n" ] } ], "source": [ "o = [1, 1, 2, 2]\n", "sum_o = sum(o)\n", "print(f\"sum({o}) = {sum_o}\")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sum({1, 2}) = 3\n" ] } ], "source": [ "o = {1, 1, 2, 2}\n", "sum_o = sum(o)\n", "print(f\"sum({o}) = {sum_o}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pozor, python je silně typovaný jazyk" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for +: 'int' and 'str'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[4], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m o \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m, \u001b[38;5;241m2\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m3\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;43msum\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mo\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'" ] } ], "source": [ "o = 1, 1, 2, 2, \"3\"\n", "sum(o)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`min` a `max` vrací nejmenší, resp. největší prvky." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "min([1, 2, -1, -10, 0]) = -10\n", "max([1, 2, -1, -10, 0]) = 2\n" ] } ], "source": [ "o = [1, 2, -1, -10, 0]\n", "print(f\"min({o}) = {min(o)}\")\n", "print(f\"max({o}) = {max(o)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`sorted` vrací setříděné prvky pole." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`reversed` vrací prvky pozpátku (pomocí iterátoru)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `all`, `any` a meší odbočka k `bool`\n", "`all` a `any` vrátí logické `and`, resp. `or` aplikované mezi všemi prvky." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "all([True, True, True]) = True\n", "any([True, True, True]) = True\n" ] } ], "source": [ "o = [True, True, True]\n", "print(f\"all({o}) = {all(o)}\")\n", "print(f\"any({o}) = {any(o)}\")" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "all([True, False, True]) = False\n", "any([True, False, True]) = True\n" ] } ], "source": [ "o = [True, False, True]\n", "print(f\"all({o}) = {all(o)}\")\n", "print(f\"any({o}) = {any(o)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Při této příležitosti ještě odbočíme a ukážeme si, jak Python převádí cokoli (tj. objekt jakéhokoli typy) na `bool`, tj. na `True` nebo `False`. Tento převod můžeme udělat explicitně pomocí samotné funkce `bool`, děje se ale také implicitně v blocích typu `if` nebo `while` a také při použití `all` a `any`.\n", "\n", "všechna čísla kromě 0 jsou True" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "False\n", "False\n", "True\n" ] } ], "source": [ "print(bool(0))\n", "print(bool(0.0))\n", "print(bool(0.0 + 0j))\n", "print(bool(-1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "řetězce jsou True pokud nejsou prázdné" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "True\n" ] } ], "source": [ "print(bool(\"\"))\n", "print(bool(\"0\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "kontejnery `tuple`, `list`, `dict`, `set` apod. jsou True pokud nejsou prázné" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "False\n", "True\n" ] } ], "source": [ "print(bool([]))\n", "print(bool(()))\n", "print(bool({0}))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pokud chceme otestovat jednotlivé prvky, musíme použít `all` nebo `any`\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "all({0}) = False\n" ] } ], "source": [ "print(f\"all({{0}}) = {all({0})}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pozor na all a any logiku prázdných kontejnerů, nemusí být zcela intuitivní." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "all([]) = True\n", "any([]) = False\n" ] } ], "source": [ "o = []\n", "print(f\"all({o}) = {all(o)}\")\n", "print(f\"any({o}) = {any(o)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Cvičení\n", "\n", "Rozšiřte hru oko bere z předchozí kapitoly o zaznamenávání a výpis tažených karet. T.j. uživatel se na konci hry dozví, které karty byly taženy. Použijte k tomu seznam.\n", "\n", "*Pokročilejší verze:* Místo pouhých čísel s hodnotou karet pracujte s názvy karet. Uložte si hodnoty jednotlivých karet do slovníku. \n", "\n", "Hodnoty karet:\n", "* karty 7 – 10 si nechávají hodnotu ( sedma za sedm, osma, za osm, … )\n", "* spodek a svršek za 1 bod\n", "* král za 2 body\n", "* Eso vždy za 11 (ale dvě esa mají součet 21)" ] } ], "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.9.16" } }, "nbformat": 4, "nbformat_minor": 2 }