přihlásit 6300/525702

Proměnné

Naučit se Python, znamená pochopit, jak pracuje s proměnnými.

Tohle je velmi důležitá kapitola, kterou by si měli pečlivě přečíst i zkušení programátoři, kteří neznají Python. A možná že především právě oni, jestliže nemají zkušenosti s dynamickými jazyky. V Pythonu jsou totiž proměnné něco jiného, než například v jazyce C.

Jak už určitě víte, v Pythonu jsou veškerá data představována datovými objekty v paměti počítače. Abychom s datovým objektem mohli v programu nějak rozumně pracovat, potřebujeme se na něj nějakým způsobem odkázat. Potřebujeme Pythonu říct, aby například sečetl tady tohle číslo (datový objekt) s tady tím (jiný datový objekt) a nebo aby tenhle text (datový objekt) vložil do tohoto seznamu (datový objekt).

A přesně k tomuto slouží v Pythonu proměnné, jsou to odkazy na datové objekty v paměti počítače. Začátečníkům na tom asi nepřijde nic zvláštního. Klasickým programátorům znalých klasických jazyků už asi běží mozek na plné obrátky a snaží se domyslet všechny důsledky.

Tak například, datový typ je pevně svázaný s hodnotou a ne proměnnou. Proměnná jednou může ukazovat na objekt s datovým typem int a za chvíli na objekt s datovým typem float. To jest proměnná v Pythonu může jednu chvíli jakoby obsahovat celé číslo 10 a za chvíli desetinné číslo 10.0 a takto může obsahovat (technicky přesněji ukazovat na) cokoli.

Vypadá to logicky a přirozeně, člověk si říká, tak by to snad mělo být všude, ne? A ono ne. V jazyce C a řadě dalších jazyků to není možné. V nich je datový typ svázaný s proměnnou a proměnná s pamětí. Při vytvoření proměnné se musí uvést, jaký má datový typ a pro něj se v paměti vyhradí potřebné místo. Do této proměnné (do onoho místa v paměti) je pak možno vkládat jen hodnoty příslušného typu (paměťové velikosti). To jest, když vytvoříte proměnnou s datovým typem int, můžete do ní přiřadit hodnotu 10 nebo 1000, ale nikdy 10.1. Lze to různými způsoby nějak obcházet, např. v jazyce C pomocí unionů a pointerů, v některých případech i přetypováním, ale to si s sebou zase nese další specifické problémy, které v Pythonu nemusíme řešit. Python je za nás bezpečně a spolehlivě řeší sám.

Je jasné, že tohle chování Pythonu je přirozenější, díky tomu je v něm programování jednodušší, rychlejší a k začátečníkům přátelštější. Odborník by to okomentoval tak, že Python je abstraktnější a bližší lidskému uvažování než jazyk C a jazyky jemu podobné. Není to zadarmo. Python za tyto výhodné vlastnosti platí o něco většími paměťovými nároky a menší rychlostí práce s proměnnými.

Po teoretickém úvodu jedna malá ukázka, aby si každý dovedl představit, jak se s proměnnými pracuje. Lehce upravený program Hello World.

>>> prom1 = "Hello"
>>> prom2 = "World!"
>>> print prom1, prom2
Hello World!

Program ukazuje práci se dvěma proměnnými, které jsem nazval prom1 a prom2. Znaménko = je operátor přiřazení. Právě ten způsobuje přiřazení odkazu na datový objekt do proměnné. Proměnné si můžete nazvat v rámci daných pravidel libovolně. Pravidla pro tvorbu identifikátorů (jak se tyto názvy správně nazývají) jsou jednoduchá. Pamatujte, že názvy funkcí, tříd, metod a podobně jsou taky proměnné a že na ně vztahují stejná pravidla.

Identifikátor

Tato pravidla jsou povinná, vyžaduje je Python a při jejich nedodržení hlásí chybu. Pak tu jsou ještě nepovinná pravidla – konvence. Nemusí se dodržovat, ale je dobrým zvykem je dodržovat. Zlepšují čitelnost a srozumitelnost kódu. S těmito pravidly vás budu seznamovat až ve správný čas a na správném místě. Například to, že názvy tříd by měly mít název s prvním velkým písmenem se dozvíte, až budu probírat třídy. No dobře, tak už to víte teď :-).

Jestli si teď myslíte, že proměnná je nějaké jméno, které ukazuje na datový objekt, tak je to pravda, ale není to úplně přesné. Mohou být i bezejmenné proměnné. Například u seznamu se každá jeho položka odkazuje na nějaký datový objekt. Seznam tedy není nic jiného, než posloupnost bezejmenných proměnných. Jméno má pouze tato posloupnost ako taková. K položkám pospoupnosti přistupujeme přes indexy. Více se o seznamech dozvíte v kapitole o datovém typu list. Datové objekty, které obsahují odkazy na jiné datové objekty, nazýváme kontejnery.

Na jeden datový objekt mohou v Pythonu ukazovat klidně dvě i více proměnných. Stačí přiřadit (operátorem =) jeden a ten samý datový objekt několika proměnným. Pozor. Operátor přiřazení se chová rozdílně v případě měnitelných a neměnitelných typů datových objektů.

Jestli nevíte, že datové typy v Pythonu jsou měnitelné a neměnitelné, tak jste asi přehlédli kapitolu o měnitelnosti datových typů. Její znalost je nezbytná k pochopení následujících pasáží.

Pozor, v řadě textů o Pythonu se o tom mluví matoucně jako o měnných a neměnných proměnných. Nenechte se tím zjednodušením zmást, proměnné jsou v Pythonu je jen jeden typ proměnných. Měnné a neměnné jsou až instance datových typů, na které proměnné ukazují.

Tak a teď zpátky k tomu, že operátor přiřazení funguje jinak v případě měnných a neměnných instancí datových typů. Nejlépe to pochopíme na ukázkách. Nejprve jak to funguje u neměnitelných datových typů.

>>> prom1 = 10
>>> prom2 = 10
>>> prom3 = prom2
>>> prom2 = 100
>>> prom3 = 10.0
>>> prom1 = prom3

Ukázka má šest příkazů, které vytváří a pracují s třemi proměnnými prom1, prom2, prom3 a třemi datovými objekty 10, 100 a 10.0. Nyní popíšu, co přesně tyto příkazy znamenají a dělají.

  1. První příkaz zdánlivě přiřazuje hodnotu 10 proměnné prom1 (tak to budou vnímat programátoři v jazyce C). Ve skutečnosti ale Python v paměti počítače vytvoří datový objekt typu int, který má hodnotu 10 a proměnnou prom1, která na tento datový objekt ukazuje.
  2. Druhý příkaz vytváří proměnnou prom2, která ukazuje na ten samý datový objekt typu int s hodnotou deset. To jest nevytváří se nový objekt a nyní máme dvě proměnné prom1 i prom2, které ukazují na jeden a ten samý objekt. Toto chování je obvyklé, ale v dokumentaci Pythonu se píše, že není zaručené. Tedy mohou vzniknout i dva neměnitelné objekty se stejnou hodnotou, i když se tak běžně neděje.
  3. Třetí příkaz znamená vytvoř proměnnou prom3, která bude ukazovat na ten samý objekt jako prom2. To znamená, že na náš datový objekt typu int s hodnotou 10, který je paměti jen jednou, ukazují již tři proměnné.
  4. Čtvrtý příkaz vytváří nový datový objekt typu int, tentokráte s hodnotou 100 a již existující proměnné prom 2 přiřazuje odkaz na tento nový objekt. Proměnné prom1 a prom3 i nadále odkazují na datový objekt typu int s hodnotou 10.
  5. Pátý příkaz vytváří nový datový objekt typu float s hodnotou 10, a odkaz na něj přiřazuje proměnné prom3. Zde je vidět, že nezáleží jen na hodnotě datového objektu, ale i jeho typu. Pro typ float se proto vytváří nový datový objekt, i když tu již jeden objekt s hodnotou deset (ale typu int) existuje.
  6. Co znamená šestý příkaz již určitě víte sami. Jen bych upozornil na skutečnost, že po tomto příkazu již žádná proměnná neukazuje na datový objekt typu int a s hodnotou 10. To znamená, že s ním již nemůžeme v našem programu pracovat, nemáme na něj odkaz. Tím pádem je tento objekt v paměti zbytečný a Python ho z ní odstraní. (Z výkonnostních důvodů to neudělá hned. Funguje to spíš tak, že Python čas od času prohlédne paměť, a vyháže z ní datové objekty, na které se neodkazuje žádná proměnná.)

Myslím, že na tom nebylo nic nepochopitelného. A teď si ukážeme, jak to funguje u měnitelných datových typů.

>>> prom1 = []
>>> prom2 = []
>>> prom3 = prom2
>>> prom1.append(1)
>>> prom2.append(2)
>>> prom3.append(3)
  1. První příkaz vytváří datový objekt seznam (prázdný) a odkaz na něj přiřazuje proměnné prom1. Označme si tento seznam jako alfa.
  2. Druhý příkaz vytváří nový datový objekt seznam (prázdný) a odkaz na něj přiřazuje proměnné prom2. Označme si tento seznam jako beta. Toto je ono zmiňované rozdílné chování. V případě měnitelných datových typů se vždy vytváří nový objekt, nesdílí se již existující, jako u neměnitelných typů. Toto chování je zaručené. Pokud chceme, aby dvě proměnné ukazovaly na stejný datový objekt, pak to lze provést jedině tak, jak to ukazuje třetí příkaz.
  3. Třetí příkaz přiřazuje proměnné prom3 odkaz na seznam beta, na který se už odkazuje prom2.
  4. Čtvrtý příkaz do seznamu alfa přidává položku s hodnotou 1. Tedy, úplně exaktně řečeno se vytváří neměnitelný objekt typu int s hodnotou 1 a odkaz na tento objekt se přiřazuje první volné položce seznamu. Seznam alfa teď má literál [1], seznam beta má stále literál [].
  5. Pátý příkaz do seznamu beta přidává položku s hodnotou 2. Tedy, exaktně řečeno ... však vy už víte. Seznam alfa má literál [1] seznam beta má literál [2]. Z poněkud laického pohledu má prom1 hodnotu [1], prom2 má hodnotu [2] a prom3 také hodnotu [2]. Prom2 a prom3 totiž ukazují na jeden a ten samý datový objekt, seznam beta.
  6. Šestý příkaz do seznamu beta přidává položku s hodnotou 3. Z laického pohledu prom1 stále má hodnotu [1], prom2 a prom3 mají hodnotu [2, 3].

    My však už nejsme laici a víme, že prom1 neobsahuje hodnotu [1], ale odkaz na datový objekt seznam, jehož první položka má odkaz na datový objekt int s hodnotou 1. Dále víme, že prom2 a prom3 neobsahují hodnotu [2, 3], ale odkaz na druhý datový objekt seznam, jehož první položka se odkazuje na datový objekt int s hodnotou 2 a jehož druhá položka se odkazuje na datový objekt int s hodnotou 3.

    Tudíž nás absolutně vůbec nepřekvapuje, že když pracujeme s prom2, tak se mění i prom3. Vlastně ani nechápeme, jak tohle může někoho překvapovat a jak to může nechápat. Vždyť je to tak logické, proměnné v Pythonu jsou prostě odkazy na datové objekty.

Děkuji za pozornost, to je vše.