přihlásit 4265/544794

Datové typy a typování

Python má silné a dynamické typování

V těchto pojmech má řada programátorů zmatek, neví co to přesně znamená, ale mají dojem že dynamické typování je to samé co slabé typování a jsou pak schopni tvrdit, že jazyk C je silně typovaný a Python slabě, přestože je tomu naopak. Tyto přívlastky popisují, jak programovací jazyk nakládá s proměnnými a datovými typy.

Jazyk může mít dynamické nebo statické typování. U statického typování se datový typ přiřazuje k proměnné při její deklaraci. Proměnné jsou známy již při překladu zdrojového kódu a díky tomu již v době překladu lze odhalit některá nesprávná použití proměnných a datových typů (chyby v programu). Také to umožňuje lepší optimalizaci programu na výkon. Nevýhodou je, že proměnná může nést jen hodnoty jednoho datového typu a obejít toto omezení komplikuje psaní programu.

U dynamického typování je datový typ sdružen s hodnotou. Hodnoty proměnných vznikají až za běhu programu a tak nemohou být jejich datové typy kontrolovány při kompilaci. Mohou ale být kontrolováný za běhu programu. U jazyků s dynamickým typováním může nést proměnná hodnotu různých datových typů. Také u nich lze za běhu programu datové typy, třeba třídy, modifikovat. To zlepšuje flexibilitu a snadnost programování, ale ztěžuje optimalizaci programu na výkon. Proto jazyky s dynamickým typováním jsou obecně pomalejší. V některých situacích až řádově. Takže opět (jako u vlastnosti interpretovaný/kompilovaný) stojíme před otázkou, je pro ten a ten projekt výhodnější produktivita programování nebo výkon aplikace?

Jazyk dále může mít silné nebo slabé typování. Silně typovaný jazyk provádí kontrolu typů a spolehlivě zjištuje jejich chybné použití (chyby v programu). Slabě typovaný jazyk to nedělá a špatné použití typů neumí spolehlivě detekovat. Řada programátorů s menším rozhledem má nerozlučně spojeno dynamické typování se slabým a statické se silným, ale to je omyl na jehož základě pak mylně odhadují Python.

Python má dynamické a přesto silné typování, proto se brání sčítat hrušky s jabkama:

print 'Výsledek =', 1 + "1"

Výsledek =
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Nelze sčítat datový typ int a str, tedy číslo a text.

Jazyk C má statické typování a přesto klidně sčítá hrušky s jabkama a vrací náhodný výsledek:

#include <stdio.h>
int main(int *argc, char *argv[]){
  printf("Vysledek = %d\n", (1+"1"));
  return(0);
}

Vysledek = 134513793

Přesto si řada programátorů myslí, že Python se nehodí na psaní rozsáhlých nebo důležitých věcí, protože neumožňuje psát robustní kód. O jazyku C to ovšem netvrdí. Mají pro to dva důvody.

1) Nemají zkušenosti s jazykem jako je Python a neuvědomují si, že Python má silné typování. Nesprávně ho zařazují do skupiny skriptovacích jazyků s dynamickým a slabým typováním, tedy bez kontroly a proto na Python pohlíží s despektem.

2) Myslí si, že statické typování a následná kontrola některých typů chyb již při překladu je samospasitelná nebo přinejmenší tak zásadní, že je nezbytné pro vytváření robustních programů.

To je ale iluze. To, že se program podaří zkompilovat neznamená, že v něm už nejsou chyby. Ostatně, uvedený příklad jazyka C to krásně ukazuje. Pocit uspokojení "když se to podařilo zkompilovat, tak už je vše OK" je zrádný. Není to tak. Statické typování dokáže detekovat jen množinu možných chyb. A existuje řada dalších způsobů a pomůcek, jak detekovat chyby v programu a nebo ještě lépe, jak jim předcházet. Statické typování je jen jeden z nich, je užitečný, ale nesmí se přeceňovat. Navíc statické typování samo je zároveň i jeden z významných zdrojů chyb v programu.

Ten kdo tohle nechápe a bojí se programovat bez statických typů by se měl zamyslet, jestli náhodou nedělá něco špatně.

Ani známá teze čím dřív se na chybu přijde, tím lépe neobstojí, protože u interpretovaných jazyků k prvnímu spuštění programu dochází dříve, než ke kompilaci u jazyků kompilovaných a k tomu spouštění dochází častěji, protože je to výrazně jednodušší, než spuštění kompilovaného programu.

Asi nejúčinnější způsob jak psát robustní programy je testování kódu, testování kódu a testování kódu. A to v jakémkoli jazyce. Python nabízí řadu pomůcek, jak toto testování usnadnit a automatizovat. Dále detekci chyb zlepšuje zmíněná silná kontrola typů. Předcházení chyb napomáhá stručná a přehledná syntaxe (uvádí se, že na to samé je v Pythonu potřeba napsat cca 5 × méně kódu než v jazyce C a je zatracený rozdíl mezi tím, zda kontrolujete 200 (5000) řádků lehce srozumitelného kódu nebo 1000 (25 000) řádků ne až tak lehce čitelného kódu). Dále Python předcházení chyb napomáhá syntaktickými drobnostmi.

Např. v podmínce nesmí být přiřazení, takže v Pythonu nemůže dojít k k časté a záludné chybě, kdy místo == napíšete omylem jen =. Nebo se k vymezování bloků nepoužívají závorky, které se občas zatoulají, příkazy se nemusí ukončovat středníky a podobně. To všechno jsou chyby, které každý programátor občas udělá, ale ne v Pythonu, tam k nim dojít nemůže.

Tolik k absenci statického typování, která se zveličuje.

Datové typy

Zde použitá terminologie a rozdělení datových typů je moje vlastní a nemusí odpovídat žádné učebnici nebo teorii programování.

Obecně

Datový typ je obecně druh dat, který jazyk zná a s kterým umí přímo pracovat. Základní datové typy vychází z možností hardware a jsou určeny paměťovou náročností (kolik bajtů zabírají v paměti) a významem bitů v nich obsažených. Například datový typ char (znak) zabírá 1 bajt, to je 8 bitů a tedy může vyjádřit 256 různých hodnot.

Bit je nejmenší jednotka informace, nabývá hodnot 1 nebo 0, tedy dva stavy. Pomocí dvou bitů dovedeme vyjádřit už čtyři stavy 00 01 10 11. Pomocí osmi bitů pak 2^8 (dva na osmou) stavů, což je 256. Jeden bajt je základní paměťová buňka, s kterou pracují současné počítače.

Jsou známy dva druhy charů, signed (se znaménkem) a unsigned (bez znaménka). Signed char je číslo které může nabýt hodnot -128 až 127, unsigned char je číslo, které může nabýt hodnot 0 až 255. To znamená, že stejné uspořádání bitů jednoho bajtu v paměti může představovat jiné číslo, podle toho, jestli si o něm myslíme, že má datový typ signed nebo unsigned char. Skvělá příležitost pro dělání chyb v programech. Takovýchto základních datových typů je definována celá řada, ale ne každý jazyk podporuje všechny.

Kromě základních datových typů existují i komplexnější abstraktní datové typy. Ty nejsou určeny potřebami hardware, ale potřebami programátorů. Umožňují abstrakci dat (zjednodušený pohled na data), což je nezbytné pro psaní větších programů, protože lidský mozek je schopen řešit úlohy jen do určité míry složitosti. Jednoduchým příkladem abstrakce dat budiž datový typ bod, který se skládá ze dvou čísel (souřadnic) a který může programátor používat při programování grafiky.

Je jasné, že abstrakce dat podléhá potřebám té či oné úlohy a tedy je individuální, každý programátor potřebuje jiné abstraktní datové typy. Proto lepší jazyky programátorovi umožňuje definovat si vlastní, neboli uživatelské datové typy. Například v jazyce C k tomu slouží příkaz typedef. Potřeba ještě větší abstrakce ve velkých programech pak vedla ke vzniku objektově orientovaného programování, kde se k tomuto účelu používají třídy, jenž umožňují k datům připojit i metody, které tyto data zpracovávají. Tuto metodu podporuje Python.

Na konec ještě existují vyšší datové typy. Tyto datové typy umožňují progamovacímu jazyku pracovat s jeho vlastními prvky, jako jsou třeba funkce nebo třídy jako s daty. Například předat třídu funkci jako parametr nebo ji za běhu programu modifikovat. Vyšší datové typy jsou vlastní dynamickým jazykům jako je Python. V statických jazycích jako je C nebo C# nejsou k dispozici.

A jak je to u Pythonu

Python je jazyk vyšší úrovně (high level language). To znamená, že programátorům poskytuje větší odstínění od hardware, tj. zjednodušenné základní typy, připravené obecné abstraktní typy a protože vše, včetně funkcí a tříd, je v něm objekt, tak i vyšší datové typy.

Základní datové typy které Python poskytuje:

název C ekvivalent popis
int signed int Celé číslo se znaménkem.
Minimálně 32 bitů, na 64 bit. procesorech může být větší.
float double Desetinné číslo s dvojitou přesností.
Jednoduchá přesnost v Pythonu není podporována.

Není to mnoho, to je v souladu s tím, že Python jazyk vyšší úrovně. Není třeba se obávat potíží při práci s binárními daty, tedy komunikace s programy napsanými v jazycích nižší úrovně. Za tímto účelem má Python modul struct, který je umožňuje jednoduše zpracovat (převést na vlastní datové typy).

Abstraktni datové typy zabudované přímo v jazyku (nemají ekvivalent v C):

název popis
NoneType Speciální typ s jedinou hodnotou None.
bool Speciální typ s hodnotami True a False.
long celé číslo neomezené velikosti (není to to samé, co long v C)
complex komplexní číslo
str text v 8. bitovém kódování
unicode text v kódování unicode
list seznam (pole s metodami pro práci s jeho prvky), lze např. používat i jako zásobník FIFO nebo FILO
tuple nemodifikovatelná varinata seznamu
dict slovník (datový typ známý i pod názvy hash, asociativní pole)
file otevřený soubor (jazyk C má neekvivalentní strukturu pro práci se soubory v knihovně stdio.h)

Vyšší a vnitřní datové typy jsou uvedeny v referenční příručce. Je to vyšší dívčí, kterou se začátečníci vůbec nemusí zabývat.