Proměnné a typy dat

Tušíme, že počítače pracují nejen s čísly. A navíc, není číslo jako číslo.

[4]:
promenna1 = 10         # celé číslo
promenna2 = 10.0       # reálné číslo
promenna3 = 10.0+0.0j  # komplexní číslo
promenna4 = '10'       # řetězec

print(promenna1, promenna2, promenna3, promenna4)
10 10.0 (10+0j) 10

Ve výše uvedeném případě můžeme ze všech jedniček napsat dvojky, čímž se hodnoty všech čtyřech proměnných změní. To, co se ale nezmění, něco jako povaha těchto hodnot, je tzv. typ. Může se zdát, že jde o nedůležitou kategorii, a chápat ji jako jen jako přívažek hodnoty, nicméně při rozvažování o programu hraje typ důležitou roli.

  • V závislosti na typu proměnných označuje tentýž zápis velmi odlišné operace

    • 1+2 bude 3`, protože do operace`+` vstupují čísla,

    • '1'+'2' bude '12', protože operandy "sčítání" jsou řetězce,

    • \(\langle 1,2\rangle+\langle 10,20\rangle\) bude jednou \(\langle 11,22\rangle\) a jindy \(\langle 1,2,10,20\rangle\) podle typu, který symbolizují závorky \(\langle ... \rangle\).

Statické a dynamické typování

Jak se s takovou nejednoznačností může počítačový jazyk vyrovnat? Jsou dvě možnosti:

  • Jazyk používá statické typy takže ještě před spuštěním kódu, když narazí na identifikátor proměnné, může si být jistý, jaký typ dat v ní je uschován, a vytvořit kód plně využívající dovedností daného počítače. (Pokud jsou například sčítána celá čísla, vystačí s jedinou instrukcí mikroprocesoru). Sem patří jazyky jako FORTRAN a C.

  • Jazyk používá dynamické typy, kdy typ proměnné se zjišťuje až za běhu programu. Neexistuje pak pochopiteně žádná jedna instrukce procesoru, která by všechny možné stituace zvládla. To je příklad jazyka Python. (Námi používaný interpret CPython si místo instrukcí procesoru vytváří návod (pseudokód) jak, se zachovat ať bude typ dat jakýkoli, což zpomaluje výpočet. Jsou ale i další, pokročilejší varianty, které zpomalení zmenšují.)

Rychlost výpočtu, ilustrovaná výše zmínkou o počtu intrukcí potřebných k provedení operace + není jedinou komplikací, kterou jazyk s dynamickými typy přináší.

Protože v Pythonu získá proměnná typ spolu hodnotou při exekuci přiřazovacího příkazu, musí při chápání významu operací s takovou proměnnou čtenář kódu více přemýšlet. např. pro kód p = a + b na otázku, jaký typ dat obsahuje p, nemůžeme odpovědět, aniž známe typ a a b. Na to nemusíme (nemůžeme) samozřejmě znát jejich konkrétní hodnotu, ale právě jen jejich typ. Právě ten rozhodne, co znamená +. Z dobrého kódu by mělo být zřejmé, jakého typu ta která proměnná je.

Ještě uvidíme, že do hádání typu proměnných a výrazů se v moderních IDE pouší i editor kódu, který označuje nesprávné operace a napovídá, jaké operace jsou s daným typem možné.

Při psaní kódu bychom měli vědět, jakého typu proměnná je. Zjistit typ proměnné lze za běhu pomcí funkce type a tedy kód

print(a)
print(type(a))

(v textové podobě ) vypíše nejprve hodnotu proměnné a potom i její typ.

Čtyři proměnné, jejichž hodnotu jsme si již vypsali výše, mají následující typy (spojení <class x> zatím překládejme jako "druh datové nádoby na uchovávání x"):

[5]:
print(type(promenna1), type(promenna2), type(promenna3), type(promenna4))
<class 'int'> <class 'float'> <class 'complex'> <class 'str'>

Vidíme zde následující typy proměnných/dat:

  • int ... celé číslo

  • float ... reálné číslo

  • complex ... komplexní číslo

  • str ... řetězec

Klíčové je mít na paměti, že

Proměná: typ + hodnota

Proměnné vstupují (např.) do operací i se svým typem.

Typ proměnné určuje, jaký význam bude mít zapsaná operace a jakého typu bude výsledek

 1 + 1  -  2
'1'+'1' - '11'

Hodnota proměnné pak určuje hodnotu výsledku operace.

Bez znalosti typu obou operandů nelze rozhodnout, zda je daná operace legální, např. a/b dává smysl jen pro číselné typy. Python má velmi laxní statickou kontrolu kódu, takže taková chyba bývá často odhalena až při běhu programu. (Brzy se seznámíme s příklady nástrojů, které umožňují takovou chybu odhalit dříve.)

file "settings.json":

"python.analysis.typeCheckingMode": "basic"

Typ výsledku operace je dán typem operandů

Typ proměnných musíme brát v úvahu, když provádíme operace. Následující tabulka ukazuje, co se stane když použijeme operaci * mezi různými typy. Povšimněte si, že kromě obvyklého chování čísel tu máme i množení řetězců, 'a'*4 - 'aaaa'.

  • int

    float

    complex

    str

    int

    int * int - int

    int * float - float

    int * complex - complex

    int * str - str

    float

    float * int - float

    float * float -

    float float * complex - complex

    float * str - Error

    complex

    complex * int - complex

    complex * float - complex

    complex * complex - complex

    complex * str - Error

    str

    str * int - str

    str * float - Error

    str * complex - Error

    str * str - Error

Binární operátory pro číselné výpočty

Zde je seznam nejčastějších binárních operátorů, jaké budeme používat symbol | význam --|---- + | součet - | rozdíl * | součin / | podíl ** | mocnění // | celá část podílu % | zbytek po dělení

Operace zbytku po dělení je definovaná i pro reálná čísla:

[4]:
import math
a = 314
b = a % (2*math.pi)

print(math.sin(a) , math.sin(b))
-0.15859290602857282 -0.15859290602856096

Všechny operace výše s výjimkou operace / mají tu vlastnost, že výsledek je celé číslo, jen k když jsou oba opernady celé čísla

int   * int   - int
float * int   - float
int   * float - float
float * float - float

tedy

13//12   - 1
13//12.0 - 1.0

U dělení bylo v Pythonu od verze 3 upuštěno od této vlastnosti. Může totiž být snadnou příčinou chyb, protože zápis

energy = 1/2 * m * v * v

začíná výpočtem zlomku 1/2, který má v čitateli i jmenovateli celé číslo. Pokud bychom (jak je tomu v C/C++) měli 1/2 == 0, byla by za všech okolností takto spočtená kinetická energie nulová. V verzi Python 3 se tak můžete spolehnout, že 1/2 == 0.5 protože

int   / int   - float

Nebude ale na škodu, když budete takovéto zlomky psát preventivně např. jako 1.0/2 nebo 0.5, kdyby si někdo váš kód vypůjčil do programu psaného v jiném jazyce.

Kontrolní otázky

  1. Jak zjistíte typ dat obsažených v proměnné?

  2. Jaké máme možnosti spočíst kolikrát se celé kladné číslo x vejde do jiného kladného čísla. Jak spočteme, kolik zbyde?

  3. Jakým výrazem spočteme, kolik vagónů (celé číslo) je potřeba k přepravě m tun materiálu, je-li nosnost každého n?