{ "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": 9, "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)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtuple1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"b\"\u001b[0m \u001b[0;31m# Vyhodí výjimku\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\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": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(-2, 0)\n", "3 < 3.3 < 4\n" ] } ], "source": [ "def neighbors(x):\n", " \"\"\"Vrátí celá čísla a, b menší a větší než x, tj a < x < b\"\"\"\n", " from math import ceil, floor\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\n", "# uvidíme, že funkce vrací tuple\n", "print(neighbors(-1))\n", "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", "1 2 3\n" ] } ], "source": [ "# vezmeme prvky ze seznamu\n", "a, b, c = [1, 2, 3]\n", "print(a, b, c)\n", "# a nebo z textového řetězce\n", "a, b, c = \"123\"\n", "print(a, b, c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python 3 přidává velice užitečnou funkcionalitu v podobě [*extended unpacking*](https://www.python.org/dev/peps/pep-3132/), 3.5 pak ještě [*additional unpacking generalizations*](https://www.python.org/dev/peps/pep-3132/)." ] }, { "cell_type": "code", "execution_count": 12, "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": 13, "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ů." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a<->A<->Z\n", "a↵\n", "A↵\n", "Z\n" ] } ], "source": [ "def print_all(*items, sep=\"<->\"):\n", " print(sep.join(items))\n", "\n", "\n", "arguments = (\"a\", \"A\", \"Z\")\n", "\n", "print_all(*arguments)\n", "\n", "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": 15, "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)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m6\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\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": 16, "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": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'append, clear, copy, count, extend, index, insert, pop, remove, reverse, sort'" ] }, "execution_count": 17, "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": 18, "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": 19, "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": 20, "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": 21, "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": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "True\n", "[0, 1, 2, 3]\n", "[0, 1, 2, 3, 5]\n" ] } ], "source": [ "print(a is b) # operátor is testuje identitu (objektů)\n", "from copy import copy\n", "b = copy(a) # pokud chcepe kopii, potřebujeme modul copy\n", "print(a is b)\n", "print(a == b) # operátor == testuje hodnoty\n", "b.append(5)\n", "print(a)\n", "print(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": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", "[0, 1]\n", "[7, 8, 9]\n", "[0, 2, 4, 6, 8]\n", "[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\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[:])\n", "# První dva prvky\n", "print(l[0:2])\n", "# Poslední tři prvky\n", "print(l[-3:])\n", "# Sudé prvky\n", "print(l[::2])\n", "# 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": 24, "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", "['jsem prvni', 'jedna', 'dva', 'tri', 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "l = list(range(10)) \n", "print(l)\n", "l[:1] = [\"jsem prvni\"]\n", "print(l)\n", "# 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": 25, "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", "[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)\n", "# 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í modulu `copy`. Můžeme použít ale i řez [:], tj." ] }, { "cell_type": "code", "execution_count": 26, "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 :). Setřiďte ho podle abecedy a vypište." ] }, { "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": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "True\n", "2\n" ] }, { "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)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;31m# nyní vyzkoušíme metodu index\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"b\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"B\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: 'B' is not in list" ] } ], "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)\n", "# nyní vyzkoušíme metodu index\n", "print(l.index(\"b\"))\n", "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": 26, "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": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n", "[1, 2, 3]\n" ] } ], "source": [ "print(slovnik[69]) # => 5\n", "print(slovnik[\"pole_podle_skal\"]) # => [1, 2, 3]" ] }, { "cell_type": "code", "execution_count": 28, "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)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mslovnik\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m100\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# Neexistující klíč -> vyhodí výjimku\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mKeyError\u001b[0m: 100" ] } ], "source": [ "slovnik[100] # Neexistující klíč -> vyhodí výjimku" ] }, { "cell_type": "code", "execution_count": 29, "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": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'clear, copy, fromkeys, get, items, keys, pop, popitem, setdefault, update, values'" ] }, "execution_count": 30, "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": [ "### Další varianty slovníku\n", "\n", "#### collections.OrderedDict\n", "V běžném slovníku jsou data neřazená. Pokud tedy procházíte slovníkem prvek po prvku, klíče budou dosti přeházené (podle toho, jak je zpracuje interní hashovací funkce). Alternativou je OrderedDict (seřazený slovník), který prvky za sebou řadí. Ovšem pozor: Řadí je podle toho, v jakém pořadí byly do slovníku vloženy, nikoliv podle abecedy nebo jiného kritéria." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Keys (normal dictionary): a, b, c, d, e\n", "Keys (ordered dictionary): a, b, c, d, e\n" ] } ], "source": [ "import collections\n", "pairs = ((\"a\" , 0), (\"b\", 1), (\"c\", 2), (\"d\", 3), (\"e\", 4)) # tuple tuplů\n", "normal = dict(pairs)\n", "ordered = collections.OrderedDict(pairs)\n", "\n", "print(\"Keys (normal dictionary): \" + \", \".join(key for key in normal))\n", "print(\"Keys (ordered dictionary): \" + \", \".join(key for key in ordered))" ] }, { "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": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'kule', 'srdce', 'piky', 'krize'}\n", "{'b', 'a'}\n" ] } ], "source": [ "print({\"srdce\", \"piky\", \"kule\", \"krize\"})\n", "print(set((\"a\", \"a\", \"a\", \"b\", \"b\"))) # Duplicitní prvky se odstraní" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'set' object does not support indexing", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m{\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;31m# Nelze indexovat\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'set' object does not support indexing" ] } ], "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. Pomocí vhodného kontejneru přiřaďte programovacím jazykům body podle oblíbenosti (1 - 10).\n", "2. Zjistěte, které z těchto jazyků jsou / nejsou společné s množinou `COMMON_LANGUAGES` definovanou níže.\n", " a. Přímo pomocí množinové operace, t.j. pomocí set onjektů.\n", " b. Pomocí for cyklu.\n", "\n", "Můžete doplnit implementaci níže nebo vymyslet svou vlastní hezčí." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "COMMON_LANGUAGES = {'Python', 'C', 'Java'}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pole v Numpy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Budeme trochu předbíhat, ale univerzalita základních kontejnerů může být v mnoha případech (při vědeckých výpočtech) nevýhodou - co se týče rychlosti, ale i vzhledem k tomu, že nemáme zaručený typ prvků ani rozměry pole. Proto knihovna numpy zavádí typ vícerozměrného pole (\"ndarray\"), který je extrémně rychlý (vektorové operace s ním jsou implementovány v C) a velice šikovný (umožňuje snadno pracovat s mnohorozměrnými poli i jejich komplikovanými indexy). Seznámíme se s ním v některé z dalších hodin." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Na jednoduché ukázce si ukážeme, jak se liší rychlost sčítání vektorů bez a s numpy." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Bez numpy\n", "149 ms ± 1.47 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "array1 = list(range(0, 1000000))\n", "array2 = list(range(1000000, 2000000))\n", "print(\"Bez numpy\")\n", "%timeit array3 = [array1[i] + array2[i] for i in range(0, len(array1))]" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "S numpy\n", "2.3 ms ± 20.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], "source": [ "import numpy as np\n", "array1 = np.arange(0, 1000000)\n", "array2 = np.arange(1000000, 2000000)\n", "print(\"S numpy\")\n", "%timeit array3 = array1 + array2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Jak vidíte, stejná operace (sečtení pole prvek po prvku) s využitím numpy proběhla asi 60x rychleji." ] }, { "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": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "len([1, 1, 2, 2]) = 4\n", "len((1, 1, 2, 2)) = 4\n", "len({1, 2}) = 2\n" ] } ], "source": [ "o = [1, 1, 2, 2]\n", "print(\"len(%s) = %i\" % (o, len(o)))\n", "o = 1, 1, 2, 2\n", "print(\"len(%s) = %i\" % (o, len(o)))\n", "o = {1, 1, 2, 2}\n", "print(\"len(%s) = %i\" % (o, len(o)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`sum` vrací součet prvků" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sum([1, 1, 2, 2]) = 6\n", "sum((1, 1, 2, 2)) = 6\n", "sum({1, 2}) = 3\n" ] } ], "source": [ "o = [1, 1, 2, 2]\n", "print(\"sum(%s) = %i\" % (o, sum(o)))\n", "o = 1, 1, 2, 2\n", "print(\"sum(%s) = %i\" % (o, sum(o)))\n", "o = {1, 1, 2, 2}\n", "print(\"sum(%s) = %i\" % (o, sum(o)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pozor, python je silně typovaný jazyk" ] }, { "cell_type": "code", "execution_count": 39, "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)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mo\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"3\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"sum(%s) = %i\"\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mo\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'" ] } ], "source": [ "o = 1, 1, 2, 2, \"3\"\n", "print(\"sum(%s) = %i\" % (o, sum(o)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`min` a `max` vrací nejmenší, resp. největší prvky." ] }, { "cell_type": "code", "execution_count": 40, "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(\"min(%s) = %i\" % (o, min(o)))\n", "print(\"max(%s) = %i\" % (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": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "all([True, True, True]) = 1\n", "any([True, True, True]) = 1\n", "all([True, False, True]) = 0\n", "any([True, False, True]) = 1\n" ] } ], "source": [ "o = [True, True, True]\n", "print(\"all(%s) = %i\" % (o, all(o)))\n", "print(\"any(%s) = %i\" % (o, any(o)))\n", "o = [True, False, True]\n", "print(\"all(%s) = %i\" % (o, all(o)))\n", "print(\"any(%s) = %i\" % (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": 42, "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": 43, "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": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "False\n", "True\n", "False\n" ] } ], "source": [ "print(bool([]))\n", "print(bool(()))\n", "print(bool({0}))\n", "# pokud chceme otestovat jednotlivé prvky, musíme použít all nebo any\n", "print(all({0}))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "toto už možná není zcela intuitivní" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "all([]) = True\n", "any([]) = False\n" ] } ], "source": [ "o = []\n", "print(\"all(%s) = %s\" % (o, all(o)))\n", "print(\"any(%s) = %s\" % (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. Šlo by nějak napravit bug, který jsme možná odhalili?" ] }, { "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 }