Python a ukazatele

Dotaz

Dobrý den, zajímalo by mne, zda Python zná něco jako ukazatele. Kouknul jsem na pár webových stránek, ale moudřejší z toho nejsem, vypadá to spíš, jako by toto python neuměl.

Odpověď

Ukazatele v Pythonu nejsou potreba, to se vyresi tak nejak samo. V tehle oblasti je dulezite porozumet tomu, co jsou "mutable" a "immutable" typy (nebudu zkouset to prekladat). Dulezite je to jak se chovaji pri zmene.

  • mutable typy se zmeni na miste, tj. "pointer" na objekt zustane stejny, ale zmeni se objekt (pro ty, kdo prichazeji z jazyku s pointery) - prikladem je treba list
  • immutable typy - pri zmene se vyrobi kopie puvodniho objeku "jinde v pameti", "pointer" se presmeruje na ni a puvodni verze se zapomene.

Prikladem je typ int nebo treba string (to byva pro zacinajici pythonisty prekvapujici).

Priklad (immutable):

>>> a = 1
>>> b = a
>>> a is b
True  <- "stejne pointery"
>>> a = 2
>>> a is b
False <- po zmene je "pointer na a" jiny

Příklad (mutable):

>>> c = [1, 2]
>>> d = c
>>> c is d
True <- zase "stejne pointery"
>>> c.append(3)
>>> c
[1, 2, 3]
>>> d
[1, 2, 3]
>>> c is d
True <- "mutable" objekt se zmenil, ale zustal v pameti na svem miste
a "c" i "d" stale ukazuji na stejne misto

Dodatečné upřesnění (květen 2013)

Proměnná typu ukazatel (v jiných jazycích) je prostor pro uložení adresy. Hodnota typu ukazatel je konkrétní adresa nebo konstanta typu NULL. Při odkazu přes ukazatel se musí použít speciální syntaxe.

Proměnná typu reference se podobá proměnné typu ukazatel, ale nesmí obsahovat speciální konstantu NULL. Odkaz přes referenci se provádí syntakticky stejným způsobem, jako kdybychom přímo pracovali s cílovým objektem. Rozdíl je ten, že se musí udělat jeden skok navíc. Technicky je to tedy rovněž nepřímý odkaz, ale syntakticky se zapisuje jako přímý odkaz.

Pythonovské proměnné nemůžeme chápat jako proměnné v klasických kompilovaných jazycích. Pythonovská proměnná je zachycena jako jméno spojené s referencí na cílový objekt. Technicky se tedy jméno proměnné vezme jako řetězec, použije se jako klíč vyhledávací tabulky (pythonovského slovníku) a z hodnotové části se vezme adresa. Poté se provede automatická dereference a tím se dostaneme na cílový objekt. Syntakticky to tedy vypadá jako přímá práce s pojmenovaným objektem, ale technicky je tam proti klasické referenční proměnné ještě jeden krok navíc -- vyhledávání v systémovém slovníku. Ještě jinak, hodnotová část slovníku může být chápána technicky také jako ukazatelová proměnná -- nebo proměnná typu reference (tady se to nepozná, protože dereference se provede vnitřně, což je stejné jako automaticky).

Pokud se jméno proměnné objeví na levé straně přiřazovacího příkazu, dochází vždy k okopírování adresy cílového objektu (reference). Obsah objektu se sdílí, nekopíruje se.

Pythonovská reference není vázaná na typ cílového objektu -- všechny reference jsou stejného typu. Typ cílového objektu je svázaný s tím cílovým objektem a vyhodnocuje se až za běhu.

V Pythonu mohou existovat i nepojmenované reference (tedy referenční proměnné, kterým není přiděleno jméno). Tvoří obsah všech zabudovaných kontejnerů, jako je například seznam. Pythonovský seznam je vlastně dynamicky přidělované pole adres. Obsahem seznamu nejsou samotné cílové objekty, ale odkazy na cílové objekty. Navenek se tedy seznam chová jako heterogenní struktura (z logického hlediska může obsahovat objekty rozdílných typů), z technického hlediska je to homogenní pole (adresy). I proto lze pythonovský seznam efektivně používat jako pole.

Vztah proměnná a mutable/immutable s tím tak docela nesouvisí.

Když to shrnu, místo práce s ukazateli se pracuje přímo s cílovým objektem. Technicky to znamená, že se pracuje s kopírováním adresy. Jde sice o referenci (ne o ukazatelovou hodnotu), ale technicky je to stejné a dá se to i stejně použít.