Srovnání Pythonu a Wolfram Language

Z Wikipedie, otevřené encyklopedie
Související informace naleznete také v článcích Python, Wolfram Language a Syntaxe a sémantika programovacího jazyka Wolfram Language.

Tato stránka podává srovnání základních funkcí programovacích jazyků Python a Wolfram Language. Python je široce rozšířený[1] open source programovací jazyk vytvořený v roce 1991 nizozemským programátorem Guido van Rossumem. Wolfram Language (dále jen WL) je programovací jazyk, jenž je jako součást komerční aplikace Mathematica od roku 1988 vyvíjen společností Wolfram Research vedenou Stephenem Wolframem.

Python i Wolfram Language jsou multiplatformní multiparadigmatické programovací jazyky, jejichž funkčnost zahrnuje mnoho oblastí matematiky, statistiky, zpracování a vizualizace dat, numerické simulace, práce se soubory, komunikace přes síť atd. Jejich vnitřní struktura a principy, na kterých jsou založeny, jsou však dramaticky odlišné. Python je založený na objektově orientovaném přístupu a dává přednost procedurálnímu programování, zatímco základní stavební kameny WL jsou výrazy a jejich úprava pomocí vzorů, přičemž preferované je programování funkcionální. Python využívá mutabilních datových struktur a jeho moto zní: "Vše je objekt."[2]. Naproti tomu WL používá téměř výhradně struktury imutabilní a za jeho moto lze vzít: "Vše je výraz."[3] S těmito odlišnostmi souvisí i syntaxe a základní funkce obou jazyků, kvůli čemuž nelze ke každému objektu v jazyce jednom přiřadit jeho ekvivalent z jazyka druhého. Ačkoli i ve WL lze emulovat objektově orientované programování a v Pythonu lze implementovat vzory, jedná se až o druhotné konstrukty, jež nejsou plně integrovány do jazyka.

Z výše uvedených důvodů je následující srovnání spíše orientační. Je porovnávána především funkčnost obsažená v základní verzi Pythonu bez dodatečných balíků s obdobnou funkčností ve WL. Předpokládá se přitom jistá znalost Pythonu a důraz je při popisu kladen spíše na WL neboť se jedná o méně rozšířený jazyk. Některé důležité oblasti jsou z důvodu odlišných přístupů obou jazyků vynechány úplně či zmíněny jen velmi letmo. Jedná se především o objektově orientované programování v případě Pythonu a o vzory a nahrazovací pravidla v případě WL. Nad rámec tohoto článku je též srovnání možností, které Python a WL nabízejí v oblasti matematiky. Historicky byl WL určen především pro práci s matematickými výrazy, pročež je podpora této oblasti ve WL velmi široká. Jako alternativu Python nabízí mnoho knihoven jako SciPy, SymPy či NumPy.

Srovnání je tematicky rozděleno do celků a prezentováno jako tabulky o dvou sloupcích, kde snahou bylo dát pokud v co nejvíce případech související kód na řádky o stejných pořadových číslech. Pokud není výslovně uvedeno jinak jsou v následujících tabulkách použity verze Python 3.8.10[4] a Wolfram Language 13.1.0[5].

Obecné[editovat | editovat zdroj]

Srovnání Pythonu a WL — Obecné
Python 3 Wolfram Language
Komentáře
# jednořádkový komentář

# víceřádkový...
# ...komentář
(* jednořádkový komentář *) 

(* víceřádkový...
...komentář *)
Základní interakce s příkazovou řádkou
print("Vypis!")         # vypsání výrazu pro uživatele
input("zadej vstup: ")  # získání vstupu od uživatele
quit()                  # ukončení daného sezení
exit()                  # ukončení daného sezení
Print["Vypis!"]         (* vypsání výrazu pro uživatele *)
Input["zadej vstup: "]  (* získání vstupu od uživatele *)
Quit[]  (* ukončení daného sezení; lze též jen Quit *)
Exit[]  (* ukončení daného sezení; lze též jen Exit *)
Poslední výsledek
1 + 3  # vrátí: 4
_      # vrátí: 4
"ret"  # vrátí: "ret"
_      # vrátí: "ret"

Poslední výsledek v interaktivním módu je ukládán v proměnné značené podtržítkem _. Podtržítko je v Pythonu právoplatný identifikátor a je občas používán jako zástupný symbol pro proměnnou, jejíž hodnotu nepotřebujeme. Toho lze užít například ve for cyklech, kde tělo for cyklu nezávisí na indexovací proměnné.

1 + 3  (* vrátí: 4 *)
%      (* vrátí: 4 *)
"ret"  (* vrátí: "ret" *)
%      (* vrátí: "ret" *)
%%     (* vrátí: 4 *)

Poslední výsledek je ukládán v proměnné značené procentem %. Předchozí výsledek se značí dvěma znaky procenta %%, výsledek předtím třemi znaky %%% atd.

Nápověda a definice
type(a)    # datový typ objektu a
help(a)    # získání nápovědy pro objekt a
globals()  # slovník globálních proměnných
locals()   # slovník lokálních proměnných
vars(a)    # slovník atributů objektu a
dir(a)     # seznam atributů třídy objektu a

V prostředí příkazové řádky IPython lze nápovědu vyvolat podobně jako ve WL vypsáním jednoho ? nebo dvou ?? otazníků. Každý objekt má dále mnoho tak zvaných magických metod a atributů, jejichž jména začínají a končí dvojitými podtržítky, např. __closure__. Tyto interní atributy podávají další informace o objektu.

Head[a]            (* hlavička výrazu a *)
?a                 (* nápověda pro symbol a; lze též Information[a] *)
Names["Global`*"]  (* seznam všech globálních proměnných *)
Names["cont`*"]    (* seznam všech proměnných v kontextu cont *)
Definition[a]      (* vypiš definici symbolu a *)

Na rozdíl do Pythonu nemají ve WL objekty klasické typy, ale každý výraz má hlavičku, která určuje jeho „typ“. Hlavičku daného výrazu lze zjistit funkcí Head. Podrobnější nápovědu k danému symbolu lze vyvolat použitím dvou otazníků: ??a. Výše uvedené funkce nejsou zcela ekvivalentní těm v levém sloupci. Ve WL neexistuje přímý ekvivalent Pythonských funkcí locals, vars či dir, což je do jisté míry dáno i odlišnou strukturou jazyka. Naproti tomu ve WL existují např. funkce Attributes pro výpis WL atributů pro daný symbol, funkce Options pro výpis voleb pro daný symbol atd. Funkce Definition vypíše definici daného symbolu. Pokud ale tato definice sama závisí na dalších symbolech, definice těchto se již nevypíše. Naproti tomu funkce FullDefinition vypíše rekurzivně všechny definice.

Smazání objektu
del a  # smaž objekt a

Výše uvedený kód lze psát i jako volání funkce del(a). Mazat lze tímto způsobem nejen celé objekty, ale například i jednotlivé prvky seznamů, např. del a[3] smaže čtvrtý prvek seznamu a .

Clear[a]     (* smaž hodnotu symbolu a *)
ClearAll[a]  (* smaž hodnoty symbolu a včetně metadat *)
Remove[a]    (* vyjmi symbol a ze jmenného prostoru *)
a =.         (* smaž hodnotu symbolu a *)

Funkcí Clear jsou vymazány hodnoty daného symbolu, ale tento si stále uchovává metainformace jako atributy, pokud nějaké má. Hodnoty i metainformace lze smazat funkcí ClearAll. Ale i pak zůstává daný symbol ve jmenném prostoru. Jeho úplné odstranění pak lze provést funkcí Remove. Smazat hodnotu proměnné x lze i funkcí Unset, jejíž syntaktický cukr zní x =..

Vyhodnocení kódu
eval("1 + 2*3")   # vyhodnoť výraz vypsaný v řetězci
exec("a = 1")     # proveď kód vypsaný v řetězci
compile("a = 1", "<string>", "exec")  # zkompiluj zadaný kód

Funkce compile zkompiluje zadaný kód do interní reprezentace, kterou lze vyhodnotit funkcí eval či exec. Funkce eval, pokud zavolána na řetězec obsahující kód, umožňuje interpretovat tento pouze tehdy, odpovídá-li kód výrazu, který se vyhodnotí na hodnotu. Naproti tomu exec umožňuje interpretovat libovolný kód.

ToExpression["1 + 2*3"]  (* převeď výraz vypsaný v řetězci na kód... *) 
ToExpression["a = 1"]    (* ...bez ohledu na to, zda jde o výraz či blok kódu *) 

f = Compile[{{x, _Real}}, x + 1]  (* zkompiluj výraz do nízkoúrovňové reprezentace *) 
f[1.]                             (* vrátí: 2. *)

Ve WL lze s kódem nakládat jako s daty a tak obyčejně není třeba kód vyjadřovat jako řetězec, který je poté nutno převést na kód. Pokud to potřeba je, lze použít funkci ToExpression. Ve WL existuje funkce Compile, tato má ale odlišnou funkci od funkce compile v Pythonu. Funkce Compile slouží ke zkompilování zadaného kódu, v příkladu výše kódu x + 1, do nízkoúrovňové rychlejší reprezentace. Modernější a robustnější alternativou ke Compile je FunctionCompile a s ní spojená rodina funkcí[6].

Provádění kódu ve skriptu V prostředí systémové příkazové řádky (zde pro konkrétnost Bash):
$ python3 skript.py  # provedení skriptu
$ python3 -m modul   # provedení modulu jako skriptu

Provedení modulu jako skriptu lze provést pomocí parametru -m. Parametry skriptu následují na příkazové řádce jeho jméno a jsou uloženy do proměnné argv v balíku sys, jenž je nutno před jeho použitím importovat. Skripty umožňují využití shebangu na UNIXových systémech.

V prostředí systémové příkazové řádky (zde pro konkrétnost Bash):
$ wolframscript -f balik.wls       # aktualizuje $ScriptCommandLine
$ WolframKernel -script balik.wls  # nechá $ScriptCommandLine prázdnou

Skript lze provést buď přímo voláním výpočetního jádra WL příkazem WolframKernel(popřípadě alternativ v závislosti na operačním systému), anebo příkazem wolframscript, který provádí několik úprav pracovního prostředí jako třeba nastavení hodnoty proměnné $ScriptCommandLine. Tato proměnná obsahuje seznam parametrů pro daný skript, jež jsou vepsané na příkazové řádce. Skripty ve WL umožňují využití shebangu na UNIXových systémech.

Načítání balíčků
import numpy             # načtení balíku numpy
import numpy as np       # načtení balíku a nastavení zkratky
from numpy import *      # načtení všech funkcí/proměnných z balíku
from numpy import array  # načtení konkrétní funkce

Základní ucelenou jednotkou kódu jsou moduly, které lze importovat příkazem import. Daný modul je soubor, který lze vyhodnotit i jako skript s pomocí proměnné __name__. Složku se soubory lze přeměnit na balík, umístí-li se do ní soubor s názvem __init__.py.

Needs["Developer`"]          (* načtení balíku Developer *)
Needs["Developer`"->"dev`"]  (* načtení balíku a nastavení aliasu *)


<<balik.wl                   (* vyhodnocení balíku; též Get["balik.wl"] *)
PacletInstall["paclet"]      (* instalace pacletu *)

Základní ucelenou jednotkou kódu jsou balíky, jež lze importovat funkcí Needs. Jednodušší variantou je použití funkce Get, která při každém svém volání vyhodnotí daný balík znovu. K tomu při použití Needs nedochází. Ve WL existuje i funkce DeclarePackage, která pouze deklaruje balík a k jeho načtení dojde jen tehdy, je-li potřeba. Moderní WL obdobou Pythonského balíku je tak zvaný paclet. Paclety lze instalovat funkcí PacletInstall. Ve WL existuje i funkce Import, ta se ale stará o import dat, ne kódu.

Porovnání hodnot
a = [1, 2, 3]  # definuj objekt a
b = [1, 2, 3]  # definuj objekt b stejné hodnoty
c = a   # do proměnné c vlož odkaz na objekt odkazovaný proměnnou a
a == b  # vrátí: True; oba objekty mají stejnou hodnotu
a is b  # vrátí: False; tyto objekty ale odkazují na dvě místa v paměti
a is c  # vrátí: True; naproti tomu a i c odkazují na stejné místo
b is not c     # vrátí: True

V Pythonu jsou proměnné v podstatě odkazy na kusy paměti, ve kterých jsou uloženy odkazované objekty. Dvě proměnné mohou odkazovat na dva objekty, jejichž tvar je totožný, jsou nicméně uloženy na dvou různých místech paměti. Pro takové proměnné vrátí porovnání pomocí operátoru == pravdu, to jest True, identické porovnání is však vrátí False. Jen pokud dvě proměnné odkazují na tentýž kus paměti, vrátí porovnání pomocí is pravdu. Opakem operátoru is je is not.

a = {1, 2, 3}  (* definuj výraz a *)
b = {1, 2, 3}  (* definuj výraz b stejné hodnoty *)
a == b         (* vrátí: True; oba výrazy mají stejnou hodnotu *)
a === b        (* vrátí: True; tyto výrazy mají i stejný tvar *)
0 == 0.0       (* vrátí: True; hodnota výrazu je stejná *)
0 === 0.0      (* vrátí: False; tyto výrazy ale nejsou totožné *)
0 =!= 0.0      (* vrátí: True *)

Ve WL jsou výrazy imutabilní struktury, jejichž identita se odvíjí čistě od jejich tvaru. V kódu výše jsou do proměnných a a b uloženy dva seznamy téhož tvaru. Následkem toho vrátí porovnání těchto proměnných True nejen při porovnání hodnot a == b, ale i při porovnání jejich identit a === b. Opakem operátoru === (též SameQ) je =!= (též UnsameQ).

Číselná reprezentace objektů
hash(a)  # hash objektu a
id(a)    # jedinečné číslo identifikující objekt a

Dva objekty mohou mít tutéž hashovou hodnotu. Číslo id se používá při porovnání identit objektů, hash se používá například v případě, kdy je daný objekt klíčem ve slovníku[7].

Hash[a]        (* hash výrazu a *)

CreateUUID[a]  (* náhodně vytvořené UUID číslo výrazu a *)

Dva výrazy mohou mít tutéž hashovou hodnotu. Pro daný výraz lze ve WL vygenerovat jednoznačné UUID číslo funkcí CreateUUID, která však při opětovném volání vrací čísla jiná. Naproti tomu funkce Hash vrací na tentýž výraz vždy tutéž hash hodnotu.

Řetězce[editovat | editovat zdroj]

Srovnání Pythonu a WL — práce s řetězci
Python 3 Wolfram Language
Řetězce
"ret"              # vrátí: 'ret'
'ret'              # vrátí: 'ret'
 r"ret\\ezec"      # vrátí: 'ret\\\\ezec'
"""ret 'ezec' """  # vrátí: "ret 'ezec' "
'''ret "ezec" '''  # vrátí: 'ret "ezec" '

'ret' + 'ezec'     # vrátí: 'retezec'
'ret' 'ezec'       # vrátí: 'retezec'
3 * 'ret'          # vrátí: 'retretret'
len('retezec')     # počet znaků; vrátí: 7

Řetězce jsou typu str. Python nabízí mnoho možností, jak řetězce zapisovat — pomocí jednoduchých či dvojitých uvozovek, popř. pomocí jejich trojic. Tímto způsobem lze obejít escapeování některých speciálních znaků a odřádkování.

"ret"                     (* vrátí: "ret" *)


"ret 'ezec' "             (* vrátí: "ret 'ezec' " *)
"ret \"ezec\" "           (* vrátí: "ret "ezec" " *)

"ret" <> "ezec"           (* vrátí: "retezec" *)
StringJoin["ret","ezec"]  (* vrátí: "retezec" *)
StringRepeat["ret",3]     (* vrátí: "retretret" *)
StringLength["retezec"]   (* vrátí: 7 *)

Řetězce mají hlavičku String. WL podporuje jen jeden druh řetězců ohraničených dvojitými uvozovkami, přičemž lze používat escape sekvence podobně jako v Pythonu. Jednoduché uvozovky se používají pro označení derivací matematických funkcí: f'[x] značí první derivaci funkce f, f''[x] značí druhou derivaci atd.

Indexování řetězců
"retezec"[2]                  # vrátí: 't'
"retezec"[-3]                 # vrátí: 'z'
"retezec"[2:-3]               # vrátí: 'te'
for c in "retezec": print(c)  # cyklus přes jednotlivé znaky

Indexování začíná od nuly. Při indexování od konce se začíná od . U rozsahů není poslední index součástí rozsahu.

StringPart["retezec",3]                    (* vrátí: "t" *)
StringPart["retezec",-3]                   (* vrátí: "z" *)
StringTake["retezec",{3,-4}]               (* vrátí: "te" *)
Do[Print[c], {c, Characters["retezec"]}]   (* cyklus přes znaky *)

Indexování začíná od jedničky. Při indexování od konce se začíná od . U rozsahů je poslední index součástí rozsahu.

Formátované řetězce
chl, jab = 3, 6
# všechny následující řádky vrátí: 'kup 3 chleby a 6 jablek'
f"kup {chl} chleby a {jab} jablek"             
"kup {} chleby a {} jablek".format(chl, jab)   
"kup {1} chleby a {0} jablek".format(jab, chl)   
"kup {x} chleby a {y} jablek".format(x=chl,y=jab)

Pokročilešjí možnosti umožňuje třída Template z modulu string[8].

{chl, jab} = {3, 6};
(* všechny následující řádky vrátí: "kup 3 chleby a 6 jablek" *)
StringForm["kup `` chleby a `` jablek", chl, jab]
StringForm["kup `2` chleby a `1` jablek", jab, chl]
StringTemplate["kup `x` chleby a `y` jablek"][<|"x"->chl,"y"->jab|>]

StringForm je starší funkce, vystřídaná novou sadou funkcí, jako např. StringTemplate, pracujících se šablonami[9].

Unicode znaky
"\756"        # osmičková soustava; vrátí: 'Ǯ'
"\xf9"        # dvě šestnáctkové číslice; vrátí: 'ù'
"\u51a3"      # čtyři šestnáctkové číslice; vrátí: '冣'
"\U000051a3"  # osm šestnáctkových číslic; vrátí: '冣'
"\N{CYRILLIC CAPITAL LETTER ZHE}"  # vrátí: 'Ж'

Python umožňuje vkládat Unicode znaky v různých formátech, včetně jejich Unicode jména, viz poslední řádek výše. Ačkoli 32bitová verze uvozená znaky "\U" vyžaduje vypsat celkem osm číslic, je ve skutečnosti použito jen posledních šest[10], protože nejvyšší možný Unicode kódový bod zní 10ffff.

"\756"        (* vrátí: "Ǯ" *)
"\.f9"        (* vrátí: "ù" *)
"\:51a3"      (* vrátí: "冣" *)
"\|0051a3"    (* vrátí: "冣" *)
"\[WLjmeno]"  (* Zápis pomocí jména ve WL *)

Ne každý Unicode znak má své WL jméno, přičemž WL jméno se může u těch znaků, které ho mají, lišit od jejich Unicode jména. Tak například znak → má kódový bod U+2192, Unicode jméno "Rightwards Arrow"[11], přičemž jeho WL jméno zní "RightArrow"[12].

Převod mezi řetězci a čísly
str(42)          # vrátí: '42'
ascii('znak Ӓ')  # vrátí: "'znak \\u04d2'"
chr(1234)        # vrátí: 'Ӓ'
ord('Ӓ')         # vrátí: 1234
ToString[42]                                   (* vrátí: "42" *)
ToString["znak Ӓ",CharacterEncoding->"ASCII"]  (* vrátí: "znak \:04d2" *)
FromCharacterCode[1234]                        (* vrátí: Ӓ *)
ToCharacterCode["Ӓ"]                           (* vrátí: {1234} *)

Výše uvedený kód nelze brát jako plnohodnotné srovnání s Pythonovským kódem v levém sloupci, protože jednotlivé funkce nejsou v daných jazycích ekvivalentní. Viz např. funkci TextString či přehled funkcí pro práci s kódováním znaků[13].

Řetězcová reprezentace
### uživatelem definovaná reprezentace
class tridaR:    # vytvoř třídu tridaR
    s = 42

    # definování reprezentace pro repr
    def __repr__(self):  
        return "stav {}".format(self.s)
    
    # definování reprezentace pro str
    def __str__(self):
        return "vypis {}".format(self.s)

x = tridaR()     # vytvoř objekt x třídy tridaR

str(x)           # vrátí: 'vypis 42'
print(x)         # vypíše: 'vypis 42'
repr(x)          # vrátí: 'stav 42'
x                # vypíše: 'stav 42'
(* --- uživatelem definový formát výrazů --- *)
(* definuj výchozí reprezentaci výrazu tridaR *)
Format[tridaR[s_]] := "stav "<>ToString[s] 

x = tridaR[42];          (* vytvoř proměnnou x s hlavičkou tridaR *)

StandardForm[x]          (* vypíše: "stav 42" *)
Print[x]                 (* vypíše: "stav 42" *)
InputForm[x]             (* vypíše: tridaR[42] *)
x                        (* vypíše: "stav 42" *)

Opět, kód v levém a pravém sloupci není zcela ekvivalentní. WL umožňuje tentýž výraz vypsat či vykreslit v několika různých reprezentacích. Nízkoúrovňovou reprezentací je FullForm, matematickou notaci připomíná reprezentace TraditionalForm, kód lze vkládat v reprezentaci InputForm, výstup se ve výchozím nastavení vypisuje v reprezentaci StandardForm, atd.[14] Konstrukt Format a další funkce[15] umožňuje předefinovat vykreslování daného výrazu pro různé reprezentace.

Regulární výrazy
import re                          # regulární výrazy
re.findall('\\w\\d', 'a b1 c d2')  # vrátí: ['b1', 'd2']

Podporu regulárních výrazů lze dostat voláním modulu re[16].

(* oba následující řádky vrátí: {"b1", "d2"} *)
StringCases["a b1 c d2", RegularExpression["\\w\\d"]]    
StringCases["a b1 c d2", WordCharacter~~DigitCharacter]

Regulární výrazy lze vkládat buď pomocí výrazu RegularExpression, do nějž se vkládá řetězec se syntaxí podobnou té v Pythonu. Upřednostňovaným způsobem je ale použití výrazu StringExpression, jehož syntaktický cukrem jsou dvě vlnovky ~~ a jehož struktura je analogická struktuře vzorů. Vzory ve WL jsou v podstatě regulární výrazy na úrovni samotného kódu.

Základní práce s čísly[editovat | editovat zdroj]

Srovnání Pythonu a WL — Práce s čísly
Python 3 Wolfram Language
Základní číselné typy
3              # typ int
3.0            # typ float
3.e5           # vědecká notace
3 + 2j         # komplexní číslo, typ complex

float(3)       # převod int na float
int(3.1)       # převod float na int
float("23.1")  # převod řetězce na float
int("23")      # převod řetězce na int

Základní číselné typy jsou int, float a complex. Přesnější reprezentace čísel s plovoucí desetinnou čárkou nabízí modul decimal[17]. Modul fractions[18] nabízí reprezentaci racionálních čísel.

3                     (* typ Integer *)
3.0                   (* typ Real *)
3.*^5                 (* vědecká notace *)
3 + 2 I               (* komplexní číslo, typ Complex *)
3 / 2                 (* racionální číslo, typ Rational *)
N[3]                  (* převod Integer na Real *)
Floor[3.1]            (* převod Real na Integer, lze použít i Round[3.1] *)
ToExpression["23"]    (* převod řetězce na Integer *)
ToExpression["23.1"]  (* převod řetězce na Real *)

Základní číselné typy jsou Integer, Rational, Real a Complex.

Číselné soustavy
10       # desetinná soustava
0b1010   # dvojková soustava
0o12     # osmičková soustava
0xa      # šestnáctková soustava
bin(10)  # převod do dvojkové soustavy
oct(10)  # převod do osmičkové soustavy
hex(10)  # převod do šestnáctkové soustavy

Výše vyjádřeno číslo 10 v různých číselných soustavách.

10                     (* desetinná soustava *)
2^^1010                (* dvojková soustava *)
8^^12                  (* osmičková soustava *)
16^^a                  (* šestnáctková soustava *)
IntegerString[10, 2]   (* převod do dvojkové soustavy *)
IntegerString[10, 8]   (* převod do osmičkové soustavy *)
IntegerString[10, 16]  (* převod do šestnáctkové soustavy *)

Lze použít i BaseForm s lepším formátováním popř. IntegerDigits pro seznam jednotlivých číslic. Podporovány jsou všechny soustavy až do řádu 36.

Aritmetika
1 + 3   # vrátí: 4
1 - 3   # vrátí: -2
2 / 3   # vrátí: 0.6666666
2. / 3. # vrátí: 0.6666666
2 * 3   # vrátí: 6

Dělení celých i reálných čísel vrátí reálné číslo, tj. typ float. Python podporuje i přiřazovací verze aritmetických operátorů: +=, -=, /= a *=.

1 + 3   (* vrátí: 4 *)
1 - 3   (* vrátí: -2 *)
2 / 3   (* vrátí: 2/3 *)
2. / 3. (* vrátí: 0.666667 *)
2 * 3   (* vrátí: 6 *)
2 3     (* vrátí: 6 *)

Dělení celých čísel vrátí racionální číslo, tj. typ Rational. Dělení reálných čísel vrátí reálné číslo, tj. typ Real. Znak násobení * lze vynechat. WL též podporuje přiřazovací verze aritmetických operátorů: +=, -=, /= a *=.

Mocniny
3 ** 2     # vrátí: 9
pow(3, 2)  # vrátí: 9
3 ^ 2       (* vrátí: 9 *)
Power[3, 2]  (* vrátí: 9 *)
Celočíselné dělení a zbytek
5 // 2        # vrátí: 2
5.0 // 2.0    # vrátí: 2.0
5 % 2         # vrátí: 1
5.0 % 2.0     # vrátí: 1.0
divmod(5, 2)  # vrátí: (2, 1)
Quotient[5, 2]          (* vrátí: 2 *)
Quotient[5.0, 2.0]      (* vrátí: 2, to jest celé číslo *)
Mod[5, 2]               (* vrátí: 1 *)
Mod[5.0, 2.0]           (* vrátí: 1.0 *)
QuotientRemainder[5, 2] (* vrátí: {2, 1} *)

Funkce Div existuje, ale označuje gradient funkce. Ve WL existuje i zápis //, který ale namísto celočíselného dělení označuje postfixové volání funkce, a znak %, který však označuje obecně předchozí výsledek.

Porovnávání
3 == 2     # vrátí: False
2 != 3     # vrátí: True
2 < 3      # vrátí: True
3 <= 3     # vrátí: True
4 > 3      # vrátí: True
3 >= 3     # vrátí: True
3.0 == 3   # vrátí: True
2 < 3 < 4  # vrátí: True

Složené podmínky jsou možné, viz poslední řádek.

3 == 2     (* vrátí: False *)
2 != 3     (* vrátí: True  *)
2 < 3      (* vrátí: True  *)
3 <= 3     (* vrátí: True  *)
4 > 3      (* vrátí: True  *)
3 >= 3     (* vrátí: True  *)
3.0 == 3   (* vrátí: True  *)
2 < 3 < 4  (* vrátí: True  *)

Složené podmínky jsou možné, viz poslední řádek.

Základní matematika
abs(-2)         # absolutní hodnota; vrátí: 2
round(2.8)      # zaokrouhlování; vrátí: 3
min(3, 8, -1)   # minimum; vrátí: -1
max(3, 8, -1)   # maximum; vrátí: 8
max([3, 8, -1]) # funguje i na seznamy; vrátí: 8
sum([3, 8, -1]) # součet seznamu; vrátí: 10
sum(i**2 for i in range(4)) # součet vygenerovaných hodnot; vrátí: 14

Poslední výraz je roven součtu druhých mocnin . Využito je generátoru, který bere hodnoty ze seznamu [0, 1, 2, 3] vytvořeného voláním range(4).

Abs[-2]           (* vrátí: 2 *)
Round[2.8]        (* vrátí: 3 *)
Min[3, 8, -1]     (* vrátí: -1 *)
Max[3, 8, -1]     (* vrátí: 8 *)
Max[{3, 8, -1}]   (* vrátí: 8 *)
Total[{3, 8, -1}] (* vrátí: 10 *)
Sum[i^2, {i, 3}]  (* vrátí: 14 *)

Funkce Sum připomíná funkci Table, kde sčítání probíhá přes specifikovaný sčítací index. Na posledním řádku je vyjádřen součet prvních tří druhých mocnin , to jest 14.

Logické operace[editovat | editovat zdroj]

Srovnání Pythonu a WL — Logické operace
Python 3 Wolfram Language
Logické operace
True                     # pravda
False                    # nepravda
x and y                  # konjunkce
x or  y                  # disjunkce
not x                    # negace
"" and "neco"            # vrátí: ''
"" or "neco"             # vrátí: 'neco'
all([True, True, False]) # vrátí: False
any([True, True, False]) # vrátí: True

Hodnoty True a False jsou typu bool. Operátory and a or vykazují zkrácené vyhodnocování a pracují i na hodnotách, které nejsou True anebo False. Funkce all(iterable) vrátí True jen když jsou všechny prvky v iterable pravda. Podobně, any vrátí True jakmile alespoň jeden z prvků je True.

True                   (* pravda *)
False                  (* nepravda *)
x && y                 (* konjunkce, též And[x, y] *)
x || y                 (* disjunkce, též Or[x, y] *)
!x                     (* negace, též Not[x] *)


And[True, True, False] (* vrátí: False *)
Or[True, True, False]  (* vrátí: True *)
TrueQ[x]               (* vrátí False, pokud x není explicitně True *)
Boole[True]            (* vrátí: 1 *) 
Boole[False]           (* vrátí: 0 *)

Operátory And a Or vykazují zkrácené vyhodnocování . Výrazy typu "" && "neco" zůstávají nevyhodnoceny. Pro převod pravdivostních hodnot na ty číselné lze využít funkce Boole. Ve WL existují i funkce AllTrue, AnyTrue a NoneTrue, které testují, zda všechny prvky zadaného seznamu splňují danou podmínku (AllTrue), alespoň jeden prvek ji splňuje (AnyTrue), či ji nesplňuje žádný (NoneTrue). Ve WL mohou být výrazy i nevyhodnoceny, což v případě logických výrazů znamená, že nelze určit jejich pravdivostní hodnotu. Je-li nutno takovou hodnotu získat, lze použít funkci TrueQ.

Bitové operace
x & y   # bitový součin
x | y   # bitový součet
x ^ y   # bitová nonekvivalence
~x      # bitová negace
x << n  # bitový posuv doleva
x >> n  # bitový posuv doprava

Python podporuje i přiřazovací verze bitových operátorů: &=, |=, ^=, <<=, >>=.

BitAnd[x, y]         (* bitový součin *)
BitOr[x, y]          (* bitový součet *)
BitXor[x, y]         (* bitová nonekvivalence *)
BitNot[x]            (* bitová negace *)
BitShiftLeft[x, n]   (* bitový posuv doleva *)
BitShiftRight[x, n]  (* bitový posuv doprava *)

Bitové operátory nemají ve WL žádné vyjádření pomocí znaků ve stylu Pythonu[19].

Podmínky
if x > 0:     # podmíněný příkaz
    print(x)  # vyhodnoť tento kód, je-li podmínka pravdivá
else:
    x = 0     # jinak vyhodnoť tento kód

if x > 5:     # zřetězený podmíněný příkaz
    x = 1
elif x > 0:   # příkaz může mít tolik elif kolik chce
    print(x)
else:
    x = 0
If[x > 0,             (* podmíněný příkaz *)
    Print[x],         (* vyhodnoť tento kód, je-li podmínka pravdivá *)
    x = 0             (* jinak vyhodnoť tento kód *)
]

Which[                (* výraz Which *)
    x > 5, x = 1,     (* podmínky na lichých pozicích... *)
    x > 0, Print[x],  (* ...kód na sudých *)
    True,  x = 0      (* jako poslední podmínku lze vzít True *)
]

(* čtvrtý argument je vyhodnocen, nelze-li určit pravdivost podmínky v prvním argumentu *)
If[x > 0,     
    Print[x],
    x = 0,
    Print["x nema hodnotu"] 
]

Ve WL je podmíněný příkaz vyjádřen výrazem a to výrazem s hlavičkou If. Tento výraz má za argumenty po řadě podmínku, pak kód, jenž se vyhodnotí, je-li podmínka pravdivá, a nakonec kód, jenž se vyhodnotí, je-li podmínka nepravdivá. Výraz If má ale ještě volitelný čtvrtý argument, jenž se vyhodnotí, nelze-li určit pravdivostní hodnotu podmínky. Pokud například není do proměnné x v příkladu výše vložena žádná hodnota, nelze určit, zda x > 0 či nikoli. Dále ve WL existuje výraz Which, jenž lze chápat jako protipól konstrukce if elif elif ... else v Pythonu. Ve Which jsou výrazy na lichých pozicích vyhodnocovány jeden po druhém. Vezmeme-li si za příklad kód výše, tak je-li skutečně x > 5, je vyhodnocen kód za podmínkou, to jest x = 1, a zbytek výrazu Which je přeskočen. V nejhorším případě dojde vyhodnocování až na konec. Je-li poslední podmínka tvaru True, je vyhodnocen jí odpovídající kód vždy.

Porovnání se vzorem
x = 'ret' # vstupní proměnná
match x:  # porovnej proměnnou s jednotlivými případy
    case 'ret':
        print('x vyhovuje prvnimu pripadu')
    case 'ezec':
        print('x vyhovuje druhemu pripadu')
    case _:
        print('zadna jina hodnota nepasuje')

Od verze 3.10 podporuje Python prostřednictvím příkazu match[20][21] též porovnání výrazu se vzorem, anglicky pattern matching. V příkladu výše vypíše kód 'x vyhovuje prvnimu pripadu'. Výrazy za klíčovým slovem case se porovnávají se vstupní proměnnou jedna po druhé. Je-li nalezena shoda, vyhodnotí se kód pro daný případ, přičemž podtržítko na konci vyhovuje jakémukoliv vstupu a odpovídají kód se tedy vyhodnotí vždy, když nevyhovuje žádná z předchozích podmínek. Porovnávané výrazy mohou přitom být mnohem sofistikovanější[22].

x = "ret";
Switch[x,
    "ret",  Print["x vyhovuje prvnimu pripadu"],
    "ezec", Print["x vyhovuje druhemu pripadu"],
    _,      Print["zadna jina hodnota nepasuje"]
]

Porovnávání se vzorem je jedním ze stavebních kamenů WL a je tak silně integrován do jazyka. Mimo jiné ho lze uplatnit ve výrazu Switch, jež je obdobou příkazu switch z jiných jazyků jako C či Java. Na rozdíl od těchto jazyků se neuvádějí jednotlivé případy slovem case. Shodou okolností je ve WL podtržítko vzor označující „cokoli“ a lze ho tedy použít zcela stejně jako v příkazu match v Pythonu.

Datové struktury[editovat | editovat zdroj]

Srovnání Pythonu a WL — Datové struktury
Python 3 Wolfram Language
Datové struktury
[1, 2, 3, 4]            # list
(1, 2, 3, 4)            # tuple
{1, 2, 3, 4}            # set
frozenset({1, 2, 3, 4}) # frozenset
{'a':3, 'b':4, 'c':5}   # dict
bytes([1, 2, 3])        # bytes; vrátí: b'\x01\x02\x03'
bytearray([1, 2, 3])    # bytearray; vrátí: bytearray(b'\x01\x02\x03')

Python nabízí několik vestavěných datových struktur: list (pole, mutabilní), dict (asociativní pole, mutabilní), tuple (uspořádaná n-tice, imutabilní), set (množina, to jest každý prvek nejvíc jednou, mutabilní), frozenset („zmražená“ množina, imutabilní), bytearray (pole bytů, mutabilní), bytes (pole bytů, imutabilní). Dále je k dispozici množství dalších struktur v modulu collections.

{1, 2, 3, 4}                (* List *) 



<|"a"->3, "b"->4, "c"->5|>  (* Association *)
ByteArray[{1, 2, 3}]        (* ByteArray["AQID"] *)

WL má dvě základní datové struktury a to List (pole) a Association (asociativní pole). Kromě toho nabízí mnoho dalších specializovaných struktur jako SparseArray (řídká pole), QuantityArray (pole s fyzikálními jednotkami) či nízkoúrovňové struktury přístupné funkcí DataStructure[23]. Pole jsou implementována dvěma různými způsoby v závislosti na typu do nich vložených dat. V základním módu se WL pole chovají podobně jako pole v Pythonu. Mohou obsahovat velmi odlišné výrazy, tato reprezentace je však relativně neefektivní. Efektivnější reprezentaci, označovanou jako PackedArray, výpočetní systém použije, je-li typ prvků stejný a současně číselný.

Počet prvků
len([1, 2, 3, 4])           # vrátí: 4
len({'a':3, 'b':4, 'c':5})  # vrátí: 3
Length[{1, 2, 3, 4}]                (* vrátí: 4 *) 
Length[<|"a"->3, "b"->4, "c"->5|>]  (* vrátí: 3 *)
Příslušnost prvku
"a" in [3, "b", "a", 4]  # vrátí: True
MemberQ[{3, "b", "a", 4}, "a"]  (* vrátí: True *)
Pole
[1, "a", [2, 3], 4]           # seznam může obsahovat různé objekty
[[1, 2], [2, 3]]              # vnořené seznamy
["a", "b", "c"] + ["u", "v"]  # vrátí: ['a', 'b', 'c', 'u', 'v']

s = ["a", "b", "c", "d"]
s[0]                 # vrátí: 'a'
s[-2]                # vrátí: 'c'
s[1:3]               # vrátí: ['b', 'c']
s[0:-1:2]            # vrátí: ['a', 'c']
s[1] = "e"           # s je nyní tvaru ['a', 'e', 'c', 'd']
s[1:3] = ["f", "g"]  # s je nyní tvaru ['a', 'f', 'g', 'd']
del s[2]             # s je nyní tvaru ['a', 'f', 'd']

V Pythonu se pole nazývají seznamy, anglicky lists, jejichž prvky se vypisují do hranatých závorek. Pole jsou mutabilní struktury, jež mohou obsahovat objekty různého druhu. Indexace se provádí hranatými závorkami, začíná nulou a lze indexovat i odzadu pomocí záporných čísel. Části seznamu lze obdržet vložením rozsahu čísel ve tvaru zacatek:konec. Lze dodat i krok, ob který se mají prvky vybírat ve tvaru zacatek:konec:krok. Nové hodnoty lze přiřazovat do jednotlivých prvků i celých částí seznamu. Smazat prvek lze příkazem del. Vestavěné typy jako seznamy lze spojovat operátorem +[pozn. 1].

{1, "a", {2, 3}, 4}              (* seznam může obsahovat různé objekty *)
{{1, 2}, {2, 3}}                 (* vnořené seznamy *)
{"a", "b", "c"}~Join~{"u", "v"}  (* vrátí: {"a", "b", "c", "u", "v"} *)

s = {"a", "b", "c", "d"}
s[[1]]                  (* vrátí: "a" *)
s[[-2]]                 (* vrátí: "c" *)
s[[2;;3]]               (* vrátí: {"b", "c"} *)
s[[1;;-1;;2]]           (* vrátí: {"a", "c"} *)
s[[2]] = "e"            (* s je nyní tvaru {"a", "e", "c", "d"} *)
s[[2;;3]] = {"f", "g"}  (* s je nyní tvaru {"a", "f", "g", "d"} *)
Drop[s, {3}]            (* vrátí: {"a", "f", "d"} *)

Ve WL se pole též nazývají seznamy, jejichž prvky se zapisují do složených závorek. Pole jsou imutabilní struktury, jež mohou obsahovat jako prvky různé výrazy. Indexace se provádí dvojitými hranatými závorkami, začíná jedničkou[pozn. 2] a lze indexovat i odzadu pomocí záporných čísel. Části seznamu lze obdržet vložením rozsahu čísel ve tvaru zacatek;;konec či zacatek;;konec;;krok. Ačkoli lze měnit jednotlivé prvky či rozsahy prvků přiřazením, což je výjimka z imutability, smazat prvky již nelze. Funkce Drop vytvoří nový seznam, v němž je požadovaný prvek vynechán.

Asociativní pole
ap = {"a": 2, 5: max, print: [3, 42]}  # klíče i hodnoty mohou být různého typu
list(ap.keys())    # vrátí: ['a', 5, <built-in function print>]
list(ap.values())  # vrátí: [2, <built-in function max>, [3, 42]]
ap["a"]            # vrátí: 2

Asociativní pole se v Pythonu nazývají slovníky, anglicky dictionaries, jež lze vytvořit voláním konstruktoru dict(). Indexovat slovníky lze pomocí klíčů, ne pomocí pořadového čísla dané hodnoty. Klíče lze získat metodou keys, hodnoty slovníku pak metodou values.

ap = <|"a"->2, 5->Sin, Print->{3, 42}|> (* klíče i hodnoty mohou být různého typu *) 
Keys[ap]      (* {a, 5, Print} *)
Values[ap]    (* {2, Sin, {3, 42}} *)
ap["a"]       (* 2 *)
ap[[3]]       (* {3, 42}  *)
ap[[Key[5]]]  (* Sin *)

Ve WL se asociativní pole nazývají asociace, anglicky associations, a odpovídají výrazům s hlavičkou Association. Indexovat hodnoty lze jak pomocí klíčů, tak pomocí pořadového čísla, protože WL udržuje i informaci o pořadí prvků v asociaci. Oba přístupy mají odlišnou syntaxi — indexování klíčem se píše do jednoduchých hranatých závorek, indexování pořadím do dvojitých hranatých závorek, přičemž oba přístupy lze kombinovat a použít klíč obalený do výrazu Key uvnitř dvojitých závorek.

Cykly a iterátory[editovat | editovat zdroj]

Následující srovnání není zcela ekvivalentní, protože WL upřednostňuje funkcionální přístup. Ačkoli tedy WL obsahuje například for cykly, je snaha se těmto vyhýbat a místo nich používat mapování funkcí pomocí funkce Map či jí příbuzných funkcí. Pro tvorbu polí je též místo for cyklů často využíváno funkcí Table a Array. Dále je třeba mít na paměti, že WL indexuje od jedničky a nabízí zkrácenou syntaxi pro případy, kdy sčítací indexy skutečně od jedničky začínají. V rámci zachování konzistence mezi Pythonským a WL kódem ale v následujícím vynucujeme indexování od nuly.

Srovnání Pythonu a WL — Cykly a iterátory
Python 3 Wolfram Language
For cyklus
for i in range(3):     # for cyklus
   print("index je: ", i)

for i in range(100):   # for cyklus
   if i < 5: continue  # přeskoč jednu iteraci
   print("index je: ", i)
   if i > 10: break    # ukonči předčasně cyklus

Iterátor range vrací vzestupná čísla počínaje nulou. Příkaz list(range(3)) tak vrátí seznam [0, 1, 2].

For[i = 0, i < 3, i++, Print["Index je: ", i]]  (* for cyklus *) 
Do[Print["Index je: ", i], {i, 0, 2}]           (* alternativní tvar *) 

Do[
    If[i < 5, Continue[]];  (* přeskoč jednu iteraci *) 
    Print["Index je: ", i];
    If[i > 10, Break[]];    (* ukonči předčasně cyklus *) 
, {i, 100}]

Funkce Do představuje uhlazenější variantu funkce For, jež má kompaktnější syntaxi. We WL existuje funkce Range, která vrací seznam vzestupných čísel počínající od jedničky. Tento příkaz ale není nutno v cyklech používat.

While cyklus
i = 0;
while i < 3:  # while cyklus
   print("index je: ", i)
   i = i + 1
i = 0;
While[i < 3, Print["Index je: ", i++]]  (* while cyklus *) 


i = 0;
Until[i >= 3, Print["Index je: ", i++]]   (* repeat-until cyklus *)

Od verze 13.1 podporuje WL i repeat-until cyklus funkcí Until.

Komprehenze
[i**2 for i in range(4)]     # vrátí: [0, 1, 4, 9]
{i: i**2 for i in range(4)}  # vrátí: {0: 0, 1: 1, 2: 4, 3: 9}

{i**2 for i in range(4)}     # vrátí: {0, 1, 4, 9}
Table[i^2, {i, 0, 3}]                  (* vrátí: {0, 1, 4, 9} *)
Association[Table[i->i^2, {i, 0, 3}]]  (* vrátí: <|0->0, 1->1, 2->4, 3->9|> *)
AssociationMap[#^2&, Range[0, 3]]      (* vrátí: <|0->0, 1->1, 2->4, 3->9|> *)

Namísto komprehenzí lze použít buď mapování pomocí funkcí Map či AssociationMap, anebo použít funkcí jako Table, které explicitně pracují s indexem.

Iterace přes prvky pole
# for cyklus přes prvky
for i in ['a', 'b', 'c']:
   print("prvek je: ", i)

# prvky spolu s indexy
for i, p in enumerate(['a', 'b', 'c']):
   print("index je: ", i, " prvek je: ", p)


# for cyklus přes seřazené pole
for i in sorted([3, 1, 2]):
   print("prvek je: ", i)

# for cyklus odzadu
for i in reversed([1, 2, 3]):
   print("prvek je: ", i)

Python používá iterátory, jež lze pro danou datovou strukturu získat funkcí iter. Funkcí next lze vyvolat další hodnotu v iterátoru. Iterátory lze vytvořit pomocí generátorů, jež vrací svoji hodnotu pomocí klíčového slova yield namísto return.

(* for cyklus přes prvky *) 
Do[Print["prvek je: ", i], {i, {"a", "b", "c"}}]     (* P *)
Print["prvek je: ", #]& /@ {"a", "b", "c"}           (* F *)

(* prvky spolu s indexy *)
s = {"a", "b", "c"};
Do[Print["index je: ", i," prvek je: ", s[[i]]], {i, Range[Length[s]]}]   (* P *)
MapIndexed[Print["index je: ", #2, " prvek je: ", #1]&, {"a", "b", "c"}]  (* F *)

(* for cyklus přes seřazené pole *)
Do[Print["prvek je: ", i], {i, Sort@{3, 1, 2}}]      (* P *)
Print["prvek je: ", #]& /@ Sort[{"a", "b", "c"}]     (* F *)

(* for cyklus odzadu *)
Do[Print["prvek je: ", i], {i, Reverse@{1, 2, 3}}]   (* P *)
Print["prvek je: ", #]& /@ Reverse[{"a", "b", "c"}]  (* F *)

WL nepoužívá iterátory známé z Pythonu. Výše jsou pro každý typ for cyklu uvedeny dvě různé varianty: P v komentáři označuje procedurální variantu a F označuje variantu funkcionální. Zápisy výše přitom nejsou zcela ekvivalentní Pythonskému kódu. Například funkce Map vrací upravené pole a má tedy netriviální návratovou hodnotu. Pokud nás návratová hodnota nezajímá, lze v jednoduchých případech použít raději funkci Scan.

Iterace přes prvky asociativního pole
# for cyklus přes klíče slovníku
for i in {'a':3, 'b':4, 'c':5}:
   print("klic je: ", i)

# for cyklus přes hodnoty slovníku
for i in {'a':3, 'b':4, 'c':5}.values():
   print("hodnota je: ", i)

# for cyklus přes hodnoty slovníku
for k, h in {'a':3, 'b':4, 'c':5}.items():
   print("par je: ", k, h)
(* for cyklus přes klíče *)
Do[Print["klic je: ", i], {i, Keys[<|"a"->3, "b"->4, "c"->5|>]}] (* P *)
Print["klic je: ", #]& /@ Keys[<|"a"->3, "b"->4, "c"->5|>]       (* F *)

(* for cyklus přes hodnoty *)
Do[Print["hodnota je: ", i], {i, <|"a"->3, "b"->4, "c"->5|>}]    (* P *)
Print["hodnota je: ", #]& /@ <|"a"->3, "b"->4, "c"->5|>          (* F *)

(* for cyklus přes páry *)
Do[Print["par je: ", kh], {kh, List@@@Normal[<|"a"->3, "b"->4, "c"->5|>]}]  (* P *)
KeyValueMap[Print["par je: ", #1, #2]&, <|"a"->3, "b"->4, "c"->5|>]         (* F *)

Výše jsou pro každý typ for cyklu uvedeny dvě různé varianty: P v komentáři označuje procedurální variantu a F označuje variantu funkcionální. Zápisy výše přitom nejsou zcela ekvivalentní Pythonskému kódu. Například funkce Map vrací upravené pole a má tedy netriviální návratovou hodnotu. Pokud nás návratová hodnota nezajímá, lze v jednoduchých případech použít raději funkci Scan.

Iterace přes několik polí
# for cyklus přes dvojice
for i, j in zip(['a', 'b', 'c'], ['d', 'e', 'f']):
   print("dvojice je: ", i, j)
(* for cyklus přes dvojice... *) 
Do[Print["dvojice je: ", i], {i, Thread[{{"a", "b", "c"}, {"d", "e", "f"}}]}]

(* ...a jeho funkcionální alternativa *)
MapThread[Print["dvojice je: ", ##]&, {{"a", "b", "c"}, {"d", "e", "f"}}]

Místo Thread lze použít i Transpose se stejným účinkem. Zápis ## označuje všechny argumenty dosazené do funkce, ne jen argument první. V kódu výše lze ekvivalentně psát Print["dvojice je: ", #1, #2]&.

Mapování
list(map(lambda x: x + 1, [3, 5, -1]))                 # vrátí: [4, 6, 0]

list(map(lambda x, y: x + y, [3, 5, -1], [2, -2, 7]))  # vrátí: [5, 3, 6]

Funkce map vrátí objekt typu map, z něhož lze konstruktorem list() vytvořit seznam. Mapovat lze i funkce definované obvyklým způsobem.

Map[(# + 1)&, {3, 5, -1}]                  (* vrátí: {4, 6, 0} *) 
(# + 1)& /@ {3, 5, -1}                     (* vrátí: {4, 6, 0} *) 
MapThread[Plus, {{3, 5, -1}, {2, -2, 7}}]  (* vrátí: {5, 3, 6} *)

Mapovat lze i funkce definované obvyklým způsobem, viz třetí řádek. Funkce Map (a její příbuzní) mají dodatečný volitelný parametr specifikující úroveň výrazu, na kterou se má daná funkce aplikovat. Funkci Map lze psát i pomocí syntaktického cukru /@, viz druhý řádek. Krom funkce Map existuje ve WL i podobná funkce Apply poskytující dodatečnou funkčnost. Je-li třeba brát několik argumentů s různých seznamů, lze použít funkci MapThread.

Výběr prvků pole dle kritéria
list(filter(lambda x: x > 0, [3, 5, -1]))  # vrátí: [3, 5]

Funkce filter vrátí objekt typu filter, z něhož lze konstruktorem list() vytvořit seznam. Použít lze i funkce definované obvyklým způsobem.

Select[{3, 5, -1}, (# > 0)&]  (* vrátí: {3, 5} *)

Použít lze i funkce definované obvyklým způsobem. Ve WL existuje i funkce Cases působící podobně jako Select, která ale místo s funkcemi pracuje se vzory.

Výběr prvků pole dle rozmezí
pole = ["a", "b", "c", "d", "e", "f", "g"]
roz = slice(1, 4)
pole[roz]  # vrátí: ['b', 'c', 'd']

Konstruktor slice umožňuje specifikovat i krok, ob který mají být prvky s pole vybírány. Tento je představován volitelným třetím argumentem.

pole = {"a", "b", "c", "d", "e", "f", "g"}
roz = Span[2, 4]  (* lze též: roz = 2 ;; 4 *)
pole[[roz]]       (* vrátí: {"b", "c", "d"} *)

Výraz Span se chová velmi podobně jako slice v Pythonu. Též umožňuje doplnit třetí parametr, jež udává krok indexace.

Funkce[editovat | editovat zdroj]

Srovnání Pythonu a WL — Funkce
Python 3 Wolfram Language
Volání a přiřazení
f(3)   # volání pomocí kulatých závorek 
g = f  # funkci f přiřadíme do proměnné g
g(3)   # volání g(3) vrátí totéž co f(3)

Volání funkce se v Pythonu provádí vypsáním jména funkce, za nímž jsou v kulatých závorkách vypsány argumenty. Funkce jsou first-class objekty, takže se chovají jako jiné objekty a lze je přiřazovat do proměnných podobně jako čísla či řetězce.

f[3]   (* volání pomocí hranatých závorek *)                     
g = f  (* funkci f přiřadíme do proměnné g *)
g[3]   (* volání g[3] vrátí totéž co f[3] *)

Podobně jako v Pythonu jsou i ve WL funkce first-class objekty. Při jejich volání se ale používají hranaté závorky.

Definice funkce
def fun(arg):    # definice je uvozena slovem def 
    x = arg + 1  # lokální proměnné
    return x     # návratová hodnota


fun(3)           # vrátí: 4

Definice se uvozuje klíčovým slovem def, argumenty nemají specifikovaný datový typ a lokální proměnné není třeba předem deklarovat. Návratová hodnota se uvozuje klíčovým slovem return. Není-li návratová hodnota specifikována, použije se None. S globálními proměnnými lze v těle funkce pracovat s použitím klíčového slova global a podobně klíčové slovo nonlocal umožňuje pracovat s proměnnými, jejichž obor platnosti leží nad tím pro právě definovanou funkci.

fun[arg_] := Module[{x},  (* definice má tvar přiřazení *)
    x = arg + 1;          (* proměnné lze lokalizovat např. pomocí Module *)
    Return[x]             (* místo Return[x] stačí psát pouze x *)
]   
                  
fun[3]                    (* vrátí: 4 *)

Definice má tvar (obyčejně odloženého) přiřazení, kde na levé straně je jméno definované funkce, za níž následuje v hranatých závorkách vzor obsahující vstupní parametry, a na straně pravé je tělo funkce. Pro lokalizaci proměnných lze použít několik blokových struktur jako Module, Block či With. Nejsou-li lokální proměnné třeba, lze tyto struktury zcela vynechat. V nejjednodušším případě nemají argumenty na levé straně přiřazení specifikovaný datový typ. Návratovou hodnotu lze vepsat do výrazu Return. Je-li návratová hodnota napsána na posledním řádku funkce, lze výraz Return vynechat a napsat na řádek jen hodnotu samotnou (přičemž řádek nesmí být zakončen středníkem). Není-li návratová hodnota specifikována, použije se Null. V rámci hierarchie oborů platnosti, např. když jedna funkce je definována v těle funkce jiné, je obor platnosti té které proměnné závislý na tom, ve které blokové struktuře byla deklarována (rozdíl může činit použití bloku Block, které umožňuje dynamic scoping). Všechny proměnné, které nejsou lokalizovány (a to buď v těle funkce, anebo v těle funkce, v rámci které je daná funkce definována), jsou proměnné globální.

Výchozí hodnoty parametrů
def fun(arg=42):
    x = arg + 1  
    return x


fun()  # vrátí: 43
fun[arg_: 42] := Module[{x},
    x = arg + 1;
    Return[x]
]         

fun[]  (* vrátí: 43 *)
Pojmenované parametry
def fun(arg1, arg2):        
    return arg1 + arg2


fun(1, 2)            # vrátí: 3
fun(arg2=2, arg1=1)  # vrátí: 3
fun(1, arg2=2)       # vrátí: 3
(* definuj volby s výchozími hodnotami *)           
Options[fun] = {"arg1"->0, "arg2"->10};
fun[OptionsPattern[]] := OptionValue["arg1"] + OptionValue["arg2"]

fun["arg1"->1, "arg2"->2]  (* vrátí: 3 *)
fun["arg2"->1, "arg1"->2]  (* vrátí: 3 *)
fun["arg1"->2]             (* vrátí: 12 *)

Obdobnou funkci, jakou v Pythonu hrají pojmenované parametry, hrají ve WL volby (anglicky options), jež jsou definovány odlišným způsobem od pozičních argumentů. Ve WL je daný parametr buď poziční anebo „pojmenovaný“, nemůže být obojím. Na rozdíl od pozičních argumentů mohou být volby uvedeny v jakémkoliv pořadí anebo nemusejí být uvedeny vůbec, v kterémžto případě se použijí jejich výchozí hodnoty.

Libovolný počet argumentů
def f(*args):    # předem neurčený počet pozičních parametrů 
    print(args)

f(1)             # vypíše: (1,)
f(1,2)           # vypíše: (1, 2)
f(1,"ret",2)     # vypíše: (1, 'ret', 2)

Předem neurčený počet pozičních parametrů lze v definici funkce značit hvězdičkou předcházející identifikátor argumentů. Pro pojmenované parametry se použijí hvězdičky dvě.

f[args__] := Print[args]  (* předem neurčený počet pozičních parametrů *)    

       
f[1]            (* vypíše: 1 *)
f[1, 2]         (* vypíše: 12 *)
f[1, "ret", 2]  (* vypíše: 1ret2 *)

Předem neurčený počet pozičních parametrů lze v definici funkce značit dvěma či třemi podtržítky za identifikátorem argumentů. Dvě podtržítka označují jeden a více argumentů, tři podtržítka označují nula a více argumentů.

Dokumentační řetězce
def f(arg):        
    '''Moje funkce'''  # dokumentační řetězec
    return arg

help(f)  # vyvolání nápovědy, kde je popisek viditelný

Krátký popis funkce lze vložit do dokumentačního řetězce následující úvodní řádek definice. Tento popis je přístupný v nápovědě k funkci a je uložen jako atribut __doc__.

f::usage = "Moje funkce";  (* dokumentační řetězec *)
f[arg_] := arg


?f  (* vyvolání krátké nápovědy s viditelným popiskem *)

Krátký popis funkce f lze vložit do dokumentačního řetězce uloženého v proměnné f::usage. Tento popis je přístupný v nápovědě k funkci.

Typ parametrů
def f(a: str)->str:  # anotace pro vstupní a výstupní hodnoty
    return a + " ale prece"

f("pozde")  # vrátí: 'pozde ale prece'
f(2)        # vyvolá výjimku TypeError, protože nelze sčítat čísla s řetězci

V Pythonu nelze přímo určit datový typ přijímaných argumentů. Blízko se v tomto ohledu pohybují anotace, ty ale mají pouze popisný charakter.

f[a_String] := a <> " ale prece"  (* vstupní argument typu String *)


f["pozde"]  (* vrátí: "pozde ale prece" *)
f[2]        (* vrátí: f[2], to jest zůstane nevyhodnoceno *)

Ve WL lze specifikovat typ přijímaných argumentů. Pokud definice funkce nevyhovuje dodaným hodnotám argumentů, zůstane funkce nevyhodnocena.

Anonymní funkce
f = lambda x: x + 1  # lambda funkce, jež přičte jedničku
f(2)                 # vrátí: 3

g = lambda x, y, z: [x + y, x + z]  # více parametrů
g(7, 1, 2)                          # vrátí: [8, 9]

V Pythonu se anonymní funkce nazývají lambda funkce a uvozují se klíčovým slovem lambda.

f = (# + 1) &  (* ryzí funkce, jež přičte jedničku *)
f[2]           (* vrátí: 3 *)

g = {#1 + #2, #1 + #3} &  (* více proměnných *)
g[7, 1, 2]                (* vrátí: {8, 9} *)

g = (#1 + {##2}) &        (* alternativní zápis *)

Ve WL se anonymní funkce nazývají ryzí funkce (anglicky pure functions) a odpovídají výrazům s hlavičkou Function. Pro jejich definici existuje syntaktický cukr využívající ampersandu & pro označení ryzí funkce a křížků # pro označení vstupních argumentů. Dva křížky ## označují všechny parametry, pokud je za nimi číslo n, označuje tento konstrukt všechny parametry od toho n-tého[24].

Výjimky[editovat | editovat zdroj]

Srovnání Pythonu a WL — Výjimky
Python 3 Wolfram Language
Příkaz assert
assert x == "ret"              # pokud x != "ret", tak vyvolá výjimku
assert x == "ret", "neni ret"  # chybová hláška je nastavena na "neni ret"

Příkazy assert jsou použity jen v debugovacím módu[25]. Při nesplnění podmínky je vyvolána výjimka AssertionError, s volitelnou chybovou hláškou.

On[Assert]                      (* aktivuj Assert *)
Assert[x == "ret"]              (* pokud x != "ret", tak vypíše hlášku *)
Assert[x == "ret", "neni ret"]  (* doplňovací text "neni ret" *)
Off[Assert]                     (* deaktivuj Assert *)

Ve výchozím nastavení jsou výrazy Assert ignorovány. To lze změnit voláním On[Assert], přičemž deaktivaci lze provést voláním Off[Assert]. Pokud není podmínka ve výrazu splněna, je vrácena chybová hláška, ale vyhodnocování kódu není přerušeno. Obdobné chování jako Assert má i pár funkcí ConfirmAssert a Enclose, viz též níže.

Varování
import warnings                 # nutno importovat modul warnings
# nějaký kód...
warnings.warn("Text varování")  # vypiš varovné hlášení
# nějaký další kód...

Modul warnings nabízí pokročilou práci s varováními[26].

(* definuj text chybové hlášky přidružené k symbolu fce *)
fce::jmenohlasky = "Text hlášky s parametrem ``."; 
(* nějaký kód... *)
Message[fce::jmenohlasky, 42];  (* vypíše hlášení: "Text hlášky s parametrem 42" *)
(* nějaký další kód... *)

Přístup WL k varováním a výjimkám je odlišný od toho v Pythonu a Message nelze položit na roveň varováním. Výrazy Message lze zachytávat funkcí Check a na základě zachycených hlášení vrátit odlišný výsledek, viz níže. Hlášení lze globálně vypínat funkcí Off a opětovně zapínat funkcí On. Vypisování hlášek z daného kusu kódu lze potlačit funkcí Quiet. Vypisovat údaje o částech prováděného kódu lze i pomocí rodiny funkcí představované především funkcí Echo.

Výjimky
# nějaký kód...
try:
    # nějaký kód v němž může dojít k chybě...    
    raise ArithmeticError # anebo lze vyvolat výjimku ručně
    # nějaký další, nevyhodnocený, kód
except ArithmeticError:
    # kód obsluhy výjimky
else:
    # proběhne-li vše bez chyby, vykonej tento kód
finally:
    # v každém případě nakonec ale vykonej tento kód

Výjimky jsou představovány třídami různých typů, které vytváření stromovou strukturu vycházející z kořenové výjimky BaseException[27]. Funkci bloku kódu uvedeného klíčovým slovem finally může přebrat i konstrukt with, viz níže.

(* chybová hlášení *)
f::jmenoch = "Nastala chyba!";
Check[
    (* nějaký kód v němž může dojít k chybě...  *)
    (* anebo lze vyvolat hlášku ručně: *)
    Message[f::jmenoch]
    (* pokračuje se ve vyhodnocování kódu...  *)
, alterVyraz, f::jmenoch]
(* zachytí jen chybové hlášky typu f::jmenoch a vrátí hodnotu alterVyraz *)

(* přerušení vyhodnocování uživatelem *)
CheckAbort[
    (* nějaký kód... *)
    (* přeruš vyhodnocování; lze i klávesovou zkratkou Alt + `.`: *)
    Abort[]    
    (* nějaký další, nevyhodnocený, kód *)   
, alterVyraz]
(* zachytí Abort a vrátí hodnotu alterVyraz *)

(* nízkoúrovňová varianta... *)
Catch[
    (* nějaký kód... *)
    (* přeruš vyhodnocování kódu: *)
    Throw[vyraz, tag]  
    (* nějaký další, nevyhodnocený, kód... *)   
, tag]
(* zachytí jen ty výrazy Throw, jejichž druhý parametr je tag, a vrátí hodnotu vyraz *)

(* vysokoúrovňová varianta... *)
Enclose[
    (* nějaký kód... *)
    (* pokud vyraz nesplňuje podmínku podm, přeruš vyhodnocování kódu: *)
    ConfirmBy[vyraz, podm]  
    (* nějaký další, nevyhodnocený, kód *)   
]
(* vrať objekt Failure obsahující informace o chybě *)
(* Enclose lze uzpůsobit i tak, aby bral jen výjimky o daném tagu *)

Chybová hlášení vyvolaná funkcí Message mohou představovat nejen hlášení, ale lze s nimi nakládat i jako s výjimkami, které lze zachycovat funkcí Check. Podobně lze zachycovat funkcí CheckAbort přerušení kódu vyvolaného buď uživatelem anebo příkazem Abort. Systém výjimek je nízkoúrovňově představován párem funkcí Throw a Catch, přičemž ve verzi 12.2 byla zavedena rodina funkcí jako ConfirmBy a Enclose, které představují vysokoúrovňovou variantu tohoto přístupu. Tato rodina funkcí je jistou nadstavbou všech předchozích přístupů včetně podmínek vyvolaných příkazem Assert[28]. Pro porovnání jednotlivých přístupů viz např. [29].

Úklid kódu
with open("soubor.txt", "r") as file:
    # kód manipulující s objektem file...
    # pokud "soubor.txt" nelze otevřít či dojde k chybě při přístupu k datům,
    # není vyvolána podmínka a při opuštění bloku with je soubor zavřen a uvolněn z paměti
WithCleanup[
    (* inicializační kód *)
    file = OpenRead["soubor.txt"] 
    ,
    (* hlavní blok kódu manipulující s objektem file... *)
    ,
    (* kód, jenž se vyhodnotí bez ohledu na to, nastala-li v hlavním bloku chyba, či nikoliv *)
    Close[file]
]

Funkce WithCleanup byla zavedena ve verzi 12.2 a ve verzi 13.1.0 je stále označována jako experimentální[30].

Odkazy[editovat | editovat zdroj]

Poznámky[editovat | editovat zdroj]

  1. Ale například balík numpy předefinovává tento operátor pro numpy pole tak, aby odpovídal součtu polí.
  2. Index 0 je připuštěn, ale v souladu se zbytkem jazyka takové volání vrátí hlavičku výrazu. To jest, příkaz {3, 4, 5}[[0]] vrátí List.

Reference[editovat | editovat zdroj]

  1. TIOBE Index. TIOBE [online]. [cit. 2022-10-03]. Dostupné online. (anglicky) 
  2. Basic Python Semantics: Variables and Objects | A Whirlwind Tour of Python. jakevdp.github.io [online]. [cit. 2022-09-27]. Dostupné online. 
  3. Mathematica programming - an advanced introduction. www.mathprogramming-intro.org [online]. [cit. 2022-10-03]. Dostupné online. 
  4. Python Release Python 3.8.10. Python.org [online]. [cit. 2022-10-03]. Dostupné online. (anglicky) 
  5. Summary of New Features in 13—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-10-03]. Dostupné online. 
  6. Code Compilation—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-10-01]. Dostupné online. 
  7. python - Difference between hash() and id(). Stack Overflow [online]. [cit. 2022-09-28]. Dostupné online. (anglicky) 
  8. string — Common string operations — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-27]. Dostupné online. 
  9. Working with Templates—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-09-27]. Dostupné online. 
  10. Unicode encoding, python documentation - why a 32-bit encoding?. Stack Overflow [online]. [cit. 2022-10-01]. Dostupné online. (anglicky) 
  11. AG, Compart. Find all Unicode Characters from Hieroglyphs to Dingbats – Unicode Compart. https://www.compart.com/en/unicode/U+2192 [online]. [cit. 2022-09-27]. Dostupné online. (anglicky) 
  12. \[RightArrow]—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-09-27]. Dostupné online. 
  13. Character Operations—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-09-28]. Dostupné online. 
  14. Converting between Expressions & Strings—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-09-28]. Dostupné online. 
  15. Defining Custom Notation—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-09-28]. Dostupné online. 
  16. re — Regular expression operations — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-27]. Dostupné online. 
  17. decimal — Decimal fixed point and floating point arithmetic — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-28]. Dostupné online. 
  18. fractions — Rational numbers — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-28]. Dostupné online. 
  19. Bitwise Operations—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-09-27]. Dostupné online. 
  20. 8. Compound statements — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-28]. Dostupné online. 
  21. PEP 634 – Structural Pattern Matching: Specification | peps.python.org. peps.python.org [online]. [cit. 2022-09-28]. Dostupné online. 
  22. 4. More Control Flow Tools — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-28]. Dostupné online. 
  23. Data Structures—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-10-02]. Dostupné online. 
  24. Function (&,|->,)—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-10-03]. Dostupné online. 
  25. 7. Simple statements — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-28]. Dostupné online. 
  26. warnings — Warning control — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-28]. Dostupné online. 
  27. Built-in Exceptions — Python 3.10.7 documentation. docs.python.org [online]. [cit. 2022-09-28]. Dostupné online. 
  28. Robustness & Error Handling—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-10-03]. Dostupné online. 
  29. programming - Confirm vs Throw. Mathematica Stack Exchange [online]. [cit. 2022-09-28]. Dostupné online. (anglicky) 
  30. WithCleanup—Wolfram Language Documentation. reference.wolfram.com [online]. [cit. 2022-10-03]. Dostupné online. 

Související články[editovat | editovat zdroj]

Externí odkazy[editovat | editovat zdroj]