diff --git a/lessons/beginners/interfaces/index.md b/lessons/beginners/interfaces/index.md
new file mode 100644
index 0000000000..9d365e52de
--- /dev/null
+++ b/lessons/beginners/interfaces/index.md
@@ -0,0 +1,111 @@
+# Rozhraní
+
+Už víš že funkce ti umožňují kousek kódu:
+
+* použít (zavolat) na více místech v programu, i když definice je jen jedna,
+* vyčlenit, aby detail (jako načtení čísla od uživatele) „nezavazel“ ve větším
+ programu, který tak může být přehlednější, a
+* pojmenovat, aby bylo jasné co kód dělá i bez toho, abys musel{{a}} číst
+ samotné tělo funkce.
+
+Další výhoda funkce je, že ji můžeš jednoduše vyměnit za jinou,
+lepší funkci – pokud má ta lepší funkce stejné *rozhraní* (angl. *interface*).
+
+Aby se ti líp představovalo, o čem budeme povídat, představ si elektrickou
+zásuvku ve zdi.
+Do takové zásuvky můžeš zapojit počítač, lampu, nabíječku na mobil, vysavač,
+nebo rádio.
+Zásuvka poskytuje elektrický proud; je jedno, jak ho použiješ.
+Stejně tak je jedno jestli je „druhý konec“ zásuvky připojený k solárnímu
+panelu nebo k atomové elektrárně.
+Zásuvka poskytuje elektrický proud, a jsou u ní důležité určité parametry
+(tvar, napětí, frekvence, maximální proud) na kterých se obě strany,
+poskytovatel proudu i spotřebič, shodly.
+
+
+# Funkce jako rozhraní
+
+Podívej se na tuhle hlavičku funkce.
+Víš z ní, co ta funkce dělá a jak ji použít?
+
+```python
+def ano_nebo_ne(otazka):
+ """Zeptá se uživatele na otázku a vrátí True nebo False dle odpovědi"""
+```
+
+Podobnou funkci už jsi napsala; víš že „vevnitř“ volá `input` a ptá se na
+příkazové řádce.
+
+Co kdybys ale měla následující funkci?
+
+```python
+def ano_nebo_ne(otazka):
+ """Ukáže tlačítka "Ano" a "Ne" a až uživatel jedno zmáčkne, vrátí True
+ nebo False dle stisknutého tlačítka."""
+```
+
+
+
+Když zavoláš tuhle funkci, `ano_nebo_ne('Chutná ti čokoláda?')`, ukáže se
+okýnko se dvěma tlačítky.
+Když uživatel jedno zmáčkne, funkce vrátí True nebo False.
+
+Z hlediska programu se nic nemění: jediné co se změní je *definice funkce*;
+volání je pak stejné jako dřív.
+
+
+# Vyzkoušej si to!
+
+Najdi nějaký svůj program, který používá `ano_nebo_ne`, případně jen `print`
+a `input`.
+
+Stáhni si modul tkui.py
+do adresáře se svým programem.
+Naimportuj z něho funkce, které potřebuješ.
+Jsou k dispozici čtyři:
+
+```python
+from tkui import input, nacti_cislo, ano_nebo_ne, print
+```
+
+Tento import *přepíše* vestavěné funkce `input` a `print` variantami,
+které mají (téměř) stejné rozhraní – jen dělají něco trochu jinak.
+
+Případné vlastní definice funkcí `nacti_cislo` a `ano_nebo_ne` pak z programu
+vyndej, aby se použily ty naimportované.
+
+Program by měl fungovat stejně jako dřív!
+
+Je to tím, že tyto funkce mají stejné rozhraní jako jejich dřívější protějšky,
+tedy:
+
+* jméno, kterým se funkce volá,
+* argumenty, které bere (např. `input` bere otázku jako řetězec; `print`
+ může bere více argumentů k vypsání), a
+* návratovou hodnotu, se kterou program pracuje dál (např `input` vrací
+ řetězec; u `print` nevrací nic smysluplného).
+
+Většina z těchto informací je přímo v hlavičce funkce.
+Ty ostatní je dobré popsat v dokumentačním řetězci, aby ten, kdo chce funkci
+použít, věděl jako na to.
+
+
+# Je to dobrý nápad?
+
+Modul `tkui` je jen ilustrační. Nedoporučuju ho používat.
+
+Příkazová řádka je dělaná tak, aby byla užitečná pro programátory.
+Až se naučíš základy a vytvoříš nějaký skvělý program, přijde čas
+k logice (tzv. *backendu*) přidat část, která bude lépe použitelná pro
+uživatele – tedy okýnko nebo webovou stránku (tzv. *frontend*).
+
+Udělat hezké a funkční *uživatelské* rozhraní je ovšem většinou celkem složité,
+a často se dělá až potom, co jsou samotné „vnitřnosti“ funkční a otestované.
+Doporučuju postupovat stejně, když se programování učíš: zůstaň u základních
+`print` a `input`, dokud nezvládneš samotné programování.
+A pak se můžeš naučit něco nového!
+
+Co si ale z této lekce odnes je koncept rozhraní: při zachování několika
+informací z hlavičky je možné vyměnit funkci za něco úplně jiného.
+A stejně tak je možné jednu funkci (třeba `input`) volat ze spousty různých
+programů, pokud znáš její rozhraní.
diff --git a/lessons/beginners/interfaces/info.yml b/lessons/beginners/interfaces/info.yml
new file mode 100644
index 0000000000..c4c4128aaa
--- /dev/null
+++ b/lessons/beginners/interfaces/info.yml
@@ -0,0 +1,4 @@
+title: Rozhraní
+style: md
+attribution: Pro PyLadies Brno napsal Petr Viktorin, 2020.
+license: cc-by-sa-40
diff --git a/lessons/beginners/interfaces/static/tkui.py b/lessons/beginners/interfaces/static/tkui.py
new file mode 100644
index 0000000000..ee5ec311c7
--- /dev/null
+++ b/lessons/beginners/interfaces/static/tkui.py
@@ -0,0 +1,146 @@
+"""Modul s funkcemi pro okýnkové otázky a odpovědi:
+
+input(otazka) -> str
+
+nacti_cislo(otazka) -> int
+
+ano_nebo_ne(otazka) -> bool
+
+print(argument0, argument1, argument2, ..., argument_n, sep='')
+
+"""
+
+from tkinter import Tk, LEFT, RIGHT, BOTTOM, W
+from tkinter.ttk import Label, Button, Spinbox, Entry
+
+
+# Následující kód používá několik pokročilejších technik.
+# Není důležité *jak* je kód napsaný, ale že je možné ho napsat – a že daná
+# funkce má dané rozhraní :)
+#
+# Mimochodem; opravdové funkce input a print jsou ještě složitější; viz:
+# https://github.com/python/cpython/blob/ce105541f/Python/bltinmodule.c#L1931
+# https://github.com/python/cpython/blob/ce105541f/Python/bltinmodule.c#L1827
+
+# Funkce používají modul tkinter, který je zabudovaný v Pythonu, ale okýnka
+# s ním vytvořená nevypadají příliš profesionálně.
+# Budeš-li chtít začít psát "okýnkové" programy, doporučuji začít rovnou
+# s knihovnou jako Qt nebo GTK.
+# Na Qt máme mimochodem lekci v pokročilém kurzu:
+# viz https://naucse.python.cz/course/mi-pyt/intro/pyqt/
+
+
+def input(otazka='odpověz'):
+ """Zeptá se uživatele na otázku a vrátí odpověď jako řetězec."""
+ root = Tk()
+ root.title(otazka)
+
+ button = Button(root, text="OK", command=root.quit)
+ button.pack(side=RIGHT)
+
+ entry = Entry(root)
+ entry.pack(side=LEFT)
+
+ root.mainloop()
+
+ value = entry.get()
+ root.destroy()
+
+ return value
+
+
+def nacti_cislo(otazka='Zadej číslo'):
+ """Zeptá se uživatele na otázku a vrátí odpověď jako celé číslo."""
+ root = Tk()
+ root.title(otazka)
+
+ entry = Spinbox(root, from_=0, to=100)
+ entry.set('0')
+ entry.pack(side=LEFT)
+
+ # Předbíháme: vnořená funkce může přistupovat
+ # k proměnným "entry" a "root", které jsou
+ # lokální pro "vnější" funkci (nacti_cislo)
+
+ def ok_pressed():
+ text = entry.get()
+ try:
+ value = int(text)
+ except ValueError:
+ entry.set('sem zadej číslo!')
+ else:
+ root.quit()
+
+ button = Button(root, text="OK", command=ok_pressed)
+ button.pack(side=RIGHT)
+
+ root.mainloop()
+
+ value = int(entry.get())
+ root.destroy()
+
+ return value
+
+
+def ano_nebo_ne(otazka='Ano nebo ne?'):
+ """Dá uživateli na výběr Ano/Ne a vrátí odpověď True nebo False."""
+ root = Tk()
+ root.title(otazka)
+
+ value = False
+
+ # Předbíháme: "nonlocal" umožňuje *měnit*
+ # lokální proměnnou z vnější funkce.
+
+ def yes():
+ nonlocal value
+ value = True
+ root.quit()
+
+ def no():
+ nonlocal value
+ value = False
+ root.quit()
+
+ button = Button(root, text="Ano", command=yes)
+ button.pack(side=LEFT)
+
+ button = Button(root, text="Ne", command=no)
+ button.pack(side=RIGHT)
+
+ root.mainloop()
+ root.destroy()
+
+ return value
+
+
+
+# Předbíháme: hvězdička v *args umožní že "print" bere proměnný
+# počet argumentů; přes "args" se potom dá projít příkazem "for"
+def print(*args, sep=' ', end='', file=None, flush=False):
+ """Zobrazí dané argumenty."""
+ root = Tk()
+ root.title('print')
+
+ str_args = ''
+ for arg in args:
+ str_args = str_args + sep + str(arg)
+
+ button = Label(root, text=str_args[len(sep):] + end)
+ button.pack(anchor=W)
+
+ button = Button(root, text="OK", command=root.quit)
+ button.pack(side=BOTTOM)
+
+ root.bind('', (lambda e: root.quit()))
+ root.mainloop()
+ root.destroy()
+
+
+# A tady je trik, jak kousek kódu nespustit když se modul importuje.
+# Pro opravdové programy ale doporučuji spouštěcí modul, viz kurz.
+if __name__ == '__main__':
+ print(input())
+ print(nacti_cislo())
+ print(ano_nebo_ne())
+ print('a', 'b', 'c', sep='; ', end='-')
diff --git a/lessons/beginners/interfaces/static/yn.png b/lessons/beginners/interfaces/static/yn.png
new file mode 100644
index 0000000000..ae922071a6
Binary files /dev/null and b/lessons/beginners/interfaces/static/yn.png differ