Select Git revision
09-objekty.tex 5.82 KiB
\documentclass{beamer}
\usepackage[utf8]{inputenc}
\usepackage[czech]{babel}
\usepackage{palatino}
\usepackage{verbatim}
\usetheme{Warsaw}
\title{Programování 1: Třídy a objekty}
\author[Martin Mareš]{Martin Mareš\\\texttt{mj@ucw.cz}}
\institute{Katedra Aplikované Matematiky\\MFF UK Praha}
\date{2024}
\begin{document}
\setbeamertemplate{navigation symbols}{}
\setbeamertemplate{footline}{}
\setbeamerfont{title page}{family=\rmfamily}
\shorthandoff{"}
\begin{frame}
\titlepage
\end{frame}
\input ../slidemac.tex
% ----------------------------------------------------------------------
\begin{frame}{Definice třídy}
\verbatiminput{trida_def.py}
~
Definujeme nový typ, který má nějaké {\bf atributy} (vlastnosti)
a~{\bf metody} (funkce, operace).
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Objekty}
Vytvoříme nový objekt (automaticky zavolá {\tt \_\_init\_\_}):
\smallskip
\py{%
azor = Zvire("Azor", "Haf!")\\
azor
}{%
<Zvire object at 0x7ffff71ce2b0>
}
\smallskip
Atributy objektu:
\smallskip
\py{%
azor.zvuk
}{%
'Haf!'
}
\py{%
azor.zvuk = "Hafff!"
}{%
}
\smallskip
Metody objektu:
\smallskip
\py{%
azor.slysi\_na('Příšera')
}{%
False
}
\py{%
azor.ozvi\_se()
}{%
Azor říká: Hafff!
}
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Identita objektu}
\py{%
jezevcik = Zvire("Špagetka", "haf")\\
bernardyn = Zvire("Bernard", "HAF!!!")\\
maxipes = bernardyn\\
maxipes.jmeno = "Fík"\\
bernardyn.jmeno
}{%
'Fík'
}
\py{%
type(jezevcik)
}{%
<class 'Zvire'>
}
\py{%
id(jezevcik), id(bernardyn), id(maxipes)
}{%
(737339253592, 737339253704, 737339253704)
}
\py{%
bernardyn is maxipes
}{%
True
}
\py{%
bernardyn is jezevcik
}{%
False
}
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Protokol pro převod na řetězec}
\verbatiminput{trida_str.py}
\medskip
\py{%
hroch = Zvire("Hippo", "Humpf!")\\
hroch
}{%
Zvire(Hippo, Humpf!)
}
\py{%
print(hroch)
}{%
Hippo
}
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Protokol pro operátory}
\verbatiminput{trida_op.py}
\medskip
\py{%
hroch1 = Zvire("Hippo", "Humpf!")\\
hroch2 = Zvire("Hippo", "Humpf!")\\
hroch1 is hroch2
}{%
False
}
\py{%
hroch1 == hroch2
}{%
True
}
\smallskip
Podobně jde předefinovat všechny operátory.
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Další protokoly}
Další protokoly, které může třída implementovat:
\medskip
\begin{itemize}
\item Konverze na bool, str, int, float
\item Indexování: čtení/zápis/mazání {\it obj\/}{\bf [...]}, {\bf len(}{\it obj\/}{\bf )}
\item Přístup k~atributům: čtení/zápis/mazání {\it obj\/}{\bf .klíč}
\item Volání jako funkce
\item Iterátor pro {\bf for} {\it x\/} {\bf in} {\it objekt\/}
\end{itemize}
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Dokumentační komentáře}
\verbatiminput{trida_doc.py}
\py{%
help(Zvire)
}{%
}
\py{%
z = Zvire("Lenochod", "Zzz...")\\
help(z.slysi\_na)
}{%
}
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Dědičnost}
\verbatiminput{trida_dedicnost.py}
\py{%
k = Kocka("Příšerka", "Mňauuu")\\
k.slysi\_na("Příserka") \cmt{(speciální kočičí verze)}
}{%
False
}
\py{%
k.ozvi\_se() \cmt{(původní zvířecí metoda)}
}{%
Příšerka říká: Mňauuu
}
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Dotazy na typy}
\py{%
type(k) is Kocka
}{%
True
}
\py{%
type(k) is Zvire
}{%
False
}
\py{%
isinstance(k, Kocka)
}{%
True
}
\py{%
isinstance(k, Zvire)
}{%
True
}
\py{%
issubclass(Kocka, Zvire)
}{%
True
}
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Jak to funguje uvnitř: namespaces a scope}
{\bf Prostory jmen (namespaces):}
\medskip
\begin{itemize}
\item Zabudované funkce (třeba {\tt print})
\item Globální jména (proměnné, funkce)
\item Lokální jména uvnitř funkce (každého zavolání)
\item Jména definovaná v~třídě
\item Jména definovaná v~objektu
\end{itemize}
\medskip
Obyčejné jméno se hledá ve všech prostorech, které jsou na daném
místě v~programu \uv{vidět}. Tomu se říká {\bf scope.}
\medskip
{\tt objekt.jméno} se hledá:
\medskip
\begin{itemize}
\item V~prostoru atributů objektu
\item V~prostoru příslušné třídy
\item V~prostorech všech nadřazených tříd
\item Pozor, třída může mít více přímých předků!
\end{itemize}
\end{frame}
% ----------------------------------------------------------------------
\begin{frame}{Jak to funguje uvnitř: zabudované typy}
{\bf Zabudované typy jako int, str apod.} jsou rovněž třídy.
Volání {\tt int()} nebo {\tt int("1")} je prostě vytvoření objektu dané třídy
(nebo recyklování existujícího u~neměnných typů).
\medskip
{\bf Třída je také objekt:}
\medskip
\begin{itemize}
\item Lze psát třeba {\tt Zvire.slysi\_na}.
\item Uvnitř třídy můžeme přiřazovat do proměnných, ty jsou vidět jako
atributy třídy.
\item Vnitřek definice {\tt class} je ve skutečnosti normální program,
který se provádí uvnitř prostoru jmen třídy.
\end{itemize}
\medskip
{\bf Modul je také objekt:}
\medskip
\begin{itemize}
\item {\tt import math} ho vytvoří
\item {\tt math.random} je formálně přístup k~atributu
\end{itemize}
\medskip
{\bf Volání metody:}
\medskip
\begin{itemize}
\item {\tt alik.ozvi\_se} vytvoří pomocnou funkci, která zavolá
{\tt Zvire.ozvi\_se} a doplní jako první argument {\tt alik}.
\end{itemize}
\end{frame}
% ----------------------------------------------------------------------
\end{document}