Skip to content

Instantly share code, notes, and snippets.

@elPytel
Last active October 13, 2024 14:33
Show Gist options
  • Save elPytel/fbf572918bca5d0832f301f347735283 to your computer and use it in GitHub Desktop.
Save elPytel/fbf572918bca5d0832f301f347735283 to your computer and use it in GitHub Desktop.
Programování v Pythonu

Python

Proč vůbec jazyk Python?

Programovací jazyk Python vznikl v roce 1991 a jeho autor Guido van Rossum Wiki. Je to tedy poměrně mladý jazyk. Rossum si dal za cíl vytvořit jazyk, který by byl jednoduchý svojí syntaxí a umožnil tak co největšímu množství lidí se začít učit programovat.

Syntaxe jazyka je velmi podobná pseudo-kódu, tedy způsobu jak se popisují algoritmy, nebo postupy toho co musí počítač vykonat, než vyřeší zadanou úlohu. Python se díky tomu řadí mezi programovací jazyky, které jsou pro člověka vůbec nejčitelnější.

Co se s Pythonem dá dělat?

Jeden z nejsilnějších nástrojů Pythonu jsou jeho knihovny (moduly). Umožňují nám využívat zdrojové kódy, které naprogramoval někdo jiný. Zpravidla platí, že ať člověk řeší jakýkoliv problém v Pythonu, tak s velkou jistotou už existuje nějaká knihovna, která za nás udělá 70% práce.

Python packages

Desktopové aplikace s grafickým rozhraním

V Pythonu lze kromě aplikací pro příkazový řádek programovat i "klasické" počítačové programy s okny. Lze k tomu využít knhovny, jako jsou PyQt, PyGObject nebo Tkinter.

Tkinter

Webové aplikace

Díky nástrojům Django či Flask může člověk naprogramovat i slušné webové stránky.

Flask

Jednoduché počítačové hry

Knihovny jako Pygame, PyOpenGL nebo Panda3D umožňují vytváření jednoduchých her.

Pygame

Strojové učení a umělá inteligence

Nastala dekáda dosud největšího rozmachu umělé insteligence a Python stojí v jeho čele díky těmto knihovnám:

  • TensorFlow,
  • PyTorch,
  • Scikit-learn,
  • Pandas,
  • NumPy,
  • Matplotlib

Je v něm velice jednoduché stavět vlastní neuronové sítě a trénovat je, nebo díky komunitě Hugging Faces si můžeš předpřipravený model AI stáhnout přímo do svého počítače. Python má také k dispozici modul openai, takže pokud nechceš trénovat vlastní umělou inteligenci, ale jen využít ve svých programech toho co nějvětší odborníci v oboru vytvořili, tak to také není problém!

TensorFlow

Mikrokontrolery

Díky MicroPythonu je možné snadno programovat mikrokontrolery a jednodeskové počítače jako například Raspberry Pi.

Raspberry Pi

Tak pojďme s Pythonem začít!

Doporučená literatůra

EN

CZ

Jazyk a syntaxe

# jednoradkovy komentar

"""
Vice-radkovy
komentar
"""

Tisk na konzoli

Přidání barevného výstupu:

# Reset
Color_Off='\033[0m'       # Text Reset
NC='\033[0m'

# Regular Colors
Black='\033[0;30m'        # Black
Red='\033[0;31m'          # Red
Green='\033[0;32m'        # Green
Yellow='\033[0;33m'       # Yellow
Blue='\033[0;34m'         # Blue
Purple='\033[0;35m'       # Purple
Cyan='\033[0;36m'         # Cyan
White='\033[0;37m'        # White

print("Calculating ..." + Green + "Done" + NC)

IDE

Vývojové prostředí (zkratka IDE, anglicky integrated development environment) je software usnadňující práci programátorů.

Online

Plně dostačující vývojové prostředí v prohlížeči. Umožnuje vytvářet:

  • jednotlivé projekty
  • sdílet hotové programy
  • kooperovat v reálném čase při psaní jednoho programu.

Stránka: replit.com

Offline

Interpreter jazyka

Slouží pro spuštění programu. Kód spouští - "interpretuje" řádek po řádku. Lze jej stáhnout z oficiálních stránek, nebo například přímo v M$ store:

IDE

Pokud nechcete psát programy v poznámkovém bloku, tak je vhodné si na počítač stáhnout IDE. Mezi velmi populární varianty patří například:

VS Code

Je prostředí od Micro$oftu. Je velmi jednoduché a veškeré další funkcionality se do něj získavají pomocí rozšíření.

Rozšíření

Ty se instalují přímo ve VS Code v záložce vlevo na svislé liště (ikona tetrisu). Doporučená rozšíření:

  • Python (Micro$oft)

Můj první program

Je ustáleným zvykem pojmenovávat hlavní soubor programu nebo spouštěnou funkci main. Proto začnětě vytvořením souboru main.py. Přípona .py odkazuje na Python a uvádí, že jde o soubor se zdrojovým kódem skryptovacího (programovacího) jazyka Python.

# muj prvni program
def main():
    print("muj prvni program")
main()

Instalování balíčků (knihoven)

Instalce knihoven se provádí pomocí nástroje pip.

Nečo více o knihovnách

Time

Jednou ze základních knihoven na kterou by mohl člověk narazit je knihovna Time, tedy čas.

import time # importovani khihovny do programu

def main():
    print("something")
    time.sleep(1)  # uspani programu na 1 sekundu
    print("something2")
    
main()

Programujeme v Pythonu

Proměnné

Pojmenování věcí je to vůbec nejtěží na programování.

Dobrý nápad je většinou pojemnovávat věci tak aby z jejich názvu bylo jasné co mají obsahovat. Co když bude název několika slovný? To vůbec není problém, protože žijeme v době IDE plných:

  • našeptávačů a automatického doplnování,
  • a hromadné přejmenování je také opravdu mocný nástroj.

now only god knows how this code works

Ideální stav pojemnovávání je takový, že dojdeme do stavu kdy není potřeba psát komentář k tomu aby jsme věděli co program vykonává (a to i po půl roce co jsme ho neviděli).

spagety code

Čistý kód se pozná tak, že jej můžete číst jako prózu.

Kód s dobrými názvy proměných, tříd, funkcí... se stává samo popisným (obzvláště v Pythonu), stačí ho tedy přečíst jako větu, která nám dá sama o sobě dostatečně dobrou představu o tom co program vykonává.

Najaká užitečná videa:

Funkce

Kdy má člověk vytvořit funkci?

  • Spagety code - kód je nečitelný (příliš mnoho vnoření)
  • Opakující se kus kódu (programuji ctrl+c, ctrl+v)

Krátké video na YouTube: Why You Shouldn't Nest Your Code

OOP

K čemu je objektové programování?

Programování jde z hlediska přístupu rodělit na:

  • Funkcionální programování,
  • Objketově orientované.

Zástupcem funkcionálního programování může být například Lisp a ojektového Java.

Když se člověk dostatečně podrobně seznámí s proměnými, poly a dalšími datovými typy tak jsou na řadě "struktury". Ty nám umožnují ukládat spolu data, která k sobě patří. Může si to představit jako záznam nějakého typu. Jako příklad si uvedeme kartotéku. Můžeme si o lidech ukládat například: jméno, věk, pohlaví, místo_narození, zaměstnání.

Zde je příklad jednoho záznamu v podobě slovníku:

osoba = {
    "jméno": "Pepa",
    "věk": 30,
    "pohlaví": "muž",
    "místo_narození": "Praha",
    "zaměstnání": "elektrikář"
}

Kartotéka která uchovává pouze jeden záznam není moc užitečná. Nejspíše by jsme chtěli ukládat záznami rovnou o několika různých lidech. Co s tím? Může si vytvořit pole (v Pythonu list) pro každá atribut našeho záznamu. Jak budeme lidi přidávat do kartotéky, tak se pustupně naše seznamy prodlužují.

# Seznamy s informacemi o jednotlivých osobách
jmena = ["Pepa", "Marie", "Jakub"]
veky = [30, 25, 35]
pohlavi = ["muž", "žena", "muž"]
mista_narozeni = ["Praha", "Brno", "Ostrava"]
zamestnani = ["elektrikář", "učitelka", "lékař"]

Data takto vskutku v programu ukládat lze, není to příliš pohodlné. Zamyslete se by bylo potřeba udělat v případě:

  • přidání nového člověka (to není zas tak těžké),
  • odstranění Pepy z naší kartotéky,
  • změnění zaměstnání Marie,
  • vypsání všech záznamů, se všemi atributy, seřazených abecedně podle jména,
  • přidání atributu místo_byliště u nových záznamů.

Některé ulohy by nebyli zas tak težké, nad jinými by se zapoťil i dobrý programátor.

Nebo by jsme mohli vzít náš původní slovník a vložit jej do pole a podle potřeby přidávat další zázamy lidí. To není o nic horší přístup, ale nakonec si moc nepomůžeme!

Zde je dobré šáhnout práve po struktuře (Python narozdíl od jazyků jako například C nerozlišuje struktury a oběkty). Jednoduchá třída reprezentující člověka pak může vypadat takto:

class Clovek:
    def __init__(self, jmeno, vek, pohlavi, misto_narozeni, zamestnani):
        self.jmeno = jmeno
        self.vek = vek
        self.pohlavi = pohlavi
        self.misto_narozeni = misto_narozeni
        self.zamestnani = zamestnani

Vytvoření instance záznamu našeho Pepy:

# Vytvoření instance bez názvů atributů
pepa = Clovek("Pepa", 30, "muž", "Praha", "elektrikář")

Nyní když budeme chtít přidat další lidi do katotéky, tak použijem list instancí objektu člověk:

# Vytvoření pole lidí "kartoteka" a přidání záznamů
kartoteka = []

pepa = Clovek("Pepa", 30, "muž", "Praha", "inženýr")
marie = Clovek("Marie", 25, "žena", "Brno", "učitelka")
jakub = Clovek("Jakub", 35, "muž", "Ostrava", "lékař")

kartoteka.append(pepa)
kartoteka.append(marie)
kartoteka.append(jakub)

Není bude hledání a práce s našimi uloženými daty o poznání jednodušší. Při procházená kartotékou si většinou vystačíme s jedním cyklem a u aktuálního člověka budeme mít rovnou přístupné všechny jeho atributy. Například když budeme chtít seřadit všchny lidi abecend včetně jejich stributů, tak můžem použít metodu .sort:

# Seřazení kartotéky podle jména abecedně
kartoteka.sort(key=lambda x: x.jmeno)

Využívá se zde lambda funkce, tím si zatím nemusíme nikterakt komplikovat život. Stačí vědět že je to způsob jak říci metodě .sort podlě čeho má pole setřídit. Pokud by jsme chtěli lidi seřadit podle věku, tak by se to dalo udělat obdobně bez jakýhkoliv obtíží.

Jak by nám řekli v teleshopingu:

Ale to není vše!

  • Horst Fuchs

Objektové programování má mnohem více triků ve svém rukávu. Spojení dat do spolu souvisí k sobě programátorům nestačilo, a tak přidali k objektům ještě vlastnosti funkce, díky nimž v sobě neukládají data, ale můžou se i nějak chovat.

Ukážeme si trochu větší program, který by se dal využít v matematické knihovně:

import math

class Shape:
    def obvod(self):
        pass
    
    def plocha(self):
        pass

class Trojuhelnik(Shape):
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
    
    def obvod(self):
        return self.a + self.b + self.c
    
    def plocha(self):
        s = self.obvod() / 2
        return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))

class Obdelnik(Shape):
    def __init__(self, a, b):
        self.a = a
        self.b = b
    
    def obvod(self):
        return 2 * (self.a + self.b)
    
    def plocha(self):
        return self.a * self.b

class Kruh(Shape):
    def __init__(self, polomer):
        self.polomer = polomer
    
    def obvod(self):
        return 2 * math.pi * self.polomer
    
    def plocha(self):
        return math.pi * self.polomer ** 2

# Pole tvarů
tvary = [Trojuhelnik(3, 4, 5), Obdelnik(3, 4), Kruh(5)]

# Výpočet obvodu a plochy pro každý tvar v poli tvary
for tvar in tvary:
    print("Obvod:", tvar.obvod())
    print("Plocha:", tvar.plocha())
    print()

Co se to tam všechno děje? Kromě toho že třída Shape má vlastní metody (které nic nedělají pass), tak se využívá i pokročilejších konceptů objektového programování:

  • Dědičnost,
  • Polymorfizmus.

Pojdě si program rozebrat postupně. Nejdřív vytváříme třídu Shape, slouží nám jako taková šablona pro to co budeme dále dělat. Má dvě metody:

  • obvod,
  • plocha.

Dále vytváříme třídy Trojuhelnik, Obdelnik, Kruh, které jsou potomky tvaru a díky tomu dědí určité vlastnosti. V tomto případě je to existence funkcí na výpočet obovdu a obsahu. Každá z těchto tříd má vlastní specifické funkce:

  • konstruktor (atribudy ze kterých se vytváří instace),
  • .obvod() - která vypočte obovod daného tělesa podle správného vzorce, do kterého dosadí hodnoty, které byli uloženy při vytvoření,
  • .plocha() - obdobně má funkci na výpočet plochy.

Dále se v kódu vytváří list do kterého se uložené různé instance ruzných typů objektů.

V jednom cyklu for lze vypočítat obvod a plochu všech těles. Všimněte si že to jdeto právě díky tomu, že dědí všechny objekty stejně pojmenované funkce od rodiče Shape!

TDD - test driven development

Když se človek dostane do stavu, že má dobře pojmenované věci v programu, hluboká vnoření a opakující struktury rozpletené do přehledných funkcí, máme odelenou logiku programu od práce s konzolí a dalšími vstupy a výstupu, tak to ještě neznamená že je vše růžové a program funguje.

Programátoři přišli s konceptem testování kódu. Je to z toho důvodu že na rozdíl od matematické logiky (a jazyku Prolog, který je ní postavený) nelze u programu dokázat zda funguje a je správný. Můžete si říci: "Vždyť jsem to vyzkoušel! Spustil jsem progam a on fungoval!", ale to nám zdaleka nestačí. Pro to, aby šlo o nějaké aplikaci říci, že je funkční, tak by jsme museli otestovat všechny možné varianty jednotlivých vstupů a jejich kombinace. To pro běžnou aplikaci je nepředstavitelné množství lidské práce. Proto si pomůžeme testováním.

Pro jazyk Python existuje nástroj pytest.

pip install pytest

Program nyní jednoduše spustíme příkazem:

pytest

(Na window je možné že bude potřeba přidat aplikaci do cesty spustitelných aplikací, aby správně fungoval)

Chybu na win jde také obejít spouštěním pomocí:

python -m pytest

Teď už jen naprogramovat naše testy.

Psát ke každé funkci ještě kód který ji otestuje? To musí být strašně moc práce!

Ano, a je to přesně 2x tolik práce při psaní kódu, ale asi 1/5x práce při zkoušení aplikace a 1/10x při hledání chyb. A to už stojí za to si s tím tu práci dát.

Píšeme testy

Tak jdeme na to! Program pytest bude standardně hledat testy v adresáři, kde ho spustíme. Testy k našemu programu snadno pozná podle toho, že začínají slovem test a jsou obecně ve tvaru: text_xxx.py.

Program pytest tyto soubory prohledá a spustí každou funkci, která se jmenuje test_xxx.

Pojdme si vyzkoušet. Když spustíme pytest na prázdno (v adresáři je náš pythnový projekt, ale zatím žádné testy), tak dostaneme hlášku:

C:\Users\jerry\Python> python -m pytest
=============== test session starts ================
platform win32 -- Python 3.11.8, pytest-8.1.1, pluggy-1.4.0
rootdir: C:\Users\jerry\Python
collected 0 items                                    

============== no tests ran in 0.02s ===============

Což je dobré a říká nám tak že nemá co dělat.

Předpokládejme, že máme jednoduchý kód, který chceme otestovat. Například máme modul calculator.py obsahující funkci pro sčítání:

# calculator.py

def add(a, b):
    return a + b

Nyní vytvoříme testovací soubor test_calculator.py:

# test_calculator.py

from calculator import add

def test_addition():
    assert add(2, 3) == 5

def test_addition_negative_numbers():
    assert add(-1, 1) == 0

Ve výše uvedeném kódu jsou dvě testovací funkce: test_addition() a test_addition_negative_numbers(). Každá z těchto funkcí obsahuje jeden testovací případ, který ověřuje správnost funkce add().

C:\Users\jerry\Python> python -m pytest
=============== test session starts ================
platform win32 -- Python 3.11.8, pytest-8.1.1, pluggy-1.4.0
rootdir: C:\Users\jerry\Python
collected 2 items

test_calculator.py ..                         [100%] 

================ 2 passed in 0.02s =================

Jak můžeme vidět, tak oba testovací případy prošly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment