[python] "list comprehension" -- prozatimni zaver

Přikryl Petr prikryl na atlas.cz
Pátek Březen 26 00:38:15 CET 2010


Toto je velmi zajímavý příspěvek a na jeho
základě jsem dospěl k závěru, který uvádím...
no na závěr. Díky

Jan Bednařík napsal (rozlámal jsem a doplnil číslování kvůli odkazům)
> 
> 1) Rozhodně nepřekládat. Překlad nic neřekne začátečníkovi,
> ale ani nikomu, kdo má s programováním zkušenosti. 
> 
> "list comprehension" je obecný pojem používaný 
> v mnoha programovacích jazycích. 
> Pokud vím, tak neexistuje žádný všeobecně rozšířený překlad 
> do češtiny. A osobně se nepamatuji, že bych se setkal 
> s knihou/učebnicí/skripty, kde by to někdo překládal.
> 
> 2) Význam pojmu "list comprehension" je natolik specifický, 
> že při snaze ho přeložit se vždy dostaneme na velmi 
> tenký led. 
> 
> 3) Použití všeobecně známých pojmů z programovacích 
> jazyků jako "generátor", "konstruktor", atp. s sebou 
> ponese matoucí asociace. 
> 
> 4) Například pod pojmem "generátorový zápis" si spousta 
> lidí představí "generator expression" a těžko pochopí, 
> že to má mít úplně jiný význam.
> 
> 5) "list comprehension" je pojem používaný 
> v informatice desítky let. To že ho ještě nikdo 
> nějak rozumně nepřeložil do češtiny (tím myslím překlad 
> který by se uchytil) asi o něčem vypovídá. Myslím si, 
> že jakákoliv snaha tento pojem přeložit si vyžádá širší 
> akademickou diskusi přesahující komunitu okolo jazyka 
> Python. Zkusil bych se poptat odborníků na fakultách 
> informatiky zdejších vysokých škol. Třeba někde 
> vymysleli a používají nějaký rozumný překlad.

=================================================

ad 1) Cílem té knihy mimo jiné je, aby to někomu něco řeklo.
A ten překlad se dělá proto, aby to bylo k dispozici
pro české čtenáře. Chápu, je to trochu paradox ;)

Takže první závěr zní, rozhodně to nějak přeložím.
Originální pojem samozřejmě ponechám v závorce 
a přidám asi odkaz na http://en.wikipedia.org/wiki/List_comprehension

ad 2) Není to zase tak tenký led. Jedna věc je snažit se
přeložit "anglické slovo comprehension" a druhá věc je snažit
se najít odpovídající pojem, který vychází z významu toho
anglického pojmu. Na výše uvedeném odkazu na wikipedii se
dají najít tyto jasné stopy (list comprehension):

 - Je to SYNTAKTICKÁ KONSTRUKCE. Tím odpadají kandidáti
   typu "generovaný seznam" (protože to vyjadřuje spíš
   dynamický výsledek, než statický zápis v programu, tj.
   syntaktickou konstrukci.
   
 - Existuje i matematický pojem "set comprehension", pro který
   existuje ekvivalent "set-builder notation" -- doslova
   notace (zápis) vytvářeče množin. Je to ono známé (příklad)
   
      { x elem N: x > 0 }
      
 - Ty zmíněné jazyky jsou většinou deklarativní jazyky. 
   Mají svým způsobem blíž ke klasické matematice, kde 
   "množina vznikne, obsah splňuje vlastnosti, je".
   Ale už ono "set-builder" napovídá tomu, že v praktickém
   případě se musí nějak vybudovat...
   
ad 3) S tím částečně souhlasím. Proto se snažím o diskusi.
Protože definice pojmů jsou vždy věcí dohody. Není v tom nic
mechanického. Vstupuje do toho lidský faktor, protože je to 
nástroj pro lidi.

ad 4) Tady si dovolím oponovat. Jestli jste to pochopil
takto, tak mám radost, protože právě takhle to bylo myšleno.
Ono to totiž nemá jiný význam.

Na http://en.wikipedia.org/wiki/List_comprehension se říká,
že jde o "syntaktickou konstrukci pro vytvoření seznamu
z jiného seznamu". V deklarativních jazycích je to OK.
Ale Python je imperativní jazyk a tahle přejatá konstrukce
je elegantně použita s širší platností. List comprehension
totiž umožňuje vytvořit seznam z čehokoliv, přes co se dá
iterovat (nejen ze seznamu). A ta iterace se dá popsat
výrazem (tedy nejen příkazy) a tomu výrazu se říká 
generátorový výraz. 

Generátorový výraz je zvláštní v tom, že šikovně kombinuje
deklarativní přístup s imperativním. Deklarativně se zapisuje
a jeho možnosti se podobají generátorové funkci (která
má uvnitř yield). 

Vyhodnocením generátorového výrazu nebo zavoláním generátorové
funkce vznikne generátor (generátorový objekt). Postupným 
voláním .next() můžeme získat generované hodnoty.

ad 5) [... akademickou diskusi.] Což tímto samozřejmě činíme.
Čtou to i lidé, kteří se věnují výuce.

Postupně přejdu k závěru...

List comprehension je syntaktická konstrukce. Jejím účelem
je popsat vytvoření seznamu jaksi víc deklarativně. Protože
jde o syntaktickou konstrukci se specifickým významem, není
pravděpodobně implementována překladem na obecný generátor,
ale je to uděláno efektivněji.

Přesto ale věcně můžeme List comprehension čistě nahradit
použitím konstruktoru seznamu a do něj vloženého generátoru,
který může být definován i generátorovým výrazem. Srovnejte:

>>> lst = [ i*2 for i in range(10) ]
>>> lst
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

a generátorovým výrazem

>>> lst = list(i*2 for i in range(10))
>>> lst
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Takže list comprehension je typický "syntactic sugar", 
který může být díky tomu, že jde o speciální případ
generátoru poněkud efektivněji implementován.

A teď "set comprehension" neboli "set-builder NOTATION":

>>> mn = { i*2 for i in range(10) }
>>> mn
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18}

a generátorovým výrazem

>>> mn = set( i*2 for i in range(10) )
>>> mn
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18}

Schválně jsem to "set(" a ")" oddělil mezerou, aby bylo
poznat, jak moc je to syntaktický cukr.

Syntaktický cukr je to rozhodně u dictionary comprehension,
protože se v něm kombinuje způsob zápisu slovníkového literálu...

    d = { 1: 2, 2: 4, ...}
    
s generátorovým výrazem:

>>> d = { i: 2*i for i in range(10) }
>>> d
{0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}

Přesto to jde snadno (mechanicky) přepsat:

>>> d = dict( (i, 2*i) for i in range(10) )
>>> d
{0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}

A můžeme takto vytvořit i generovanou n-tici (tuple)...
     
>>> t = tuple( i*2 for i in range(10) )
>>> t
(0, 2, 4, 6, 8, 10, 12, 14, 16, 18)

... i když "tuple comprehension" Python nedefinuje. Troufám si 
tvrdit, že je tomu tak jen proto, protože zápis

  g = ( i*2 for i in range(10) )
  
byl vyhrazen pro zápis samostatně uvedeného generátorového 
výrazu. (Tuple je immutable, a proto má syntaktický cukr
pro generovaný obsah menší význam než u seznamu, množiny
a slovníku.)

Závěr
=====

Zhruba uvedenou úvahou jsem dříve dospěl k pojmům:
   
   generátorový zápis seznamu
   generátorový zápis slovníku
   generátorový zápis množiny
   
Z toho taky pěkně vyplynul překlad pojmu "comprehension" 
(neboli ...-builder notation) "generátorový zápis".

Cítil jsem, že "generátorový zápis" jaksi nemá punc "pojmovitosti",
protože slovo "zápis" je velmi české a hlavně obecné, snadno 
přehlédnutelné, neprovokující k uvažování, že bychom je měli
chápat neoddělitelně s předchozím "generátorový" jako jeden pojem.
U definic na wikipedii mě proto trklo do oka slovo "notace".
Takže jsem dospěl k následujícímu rozuzlení:

   comprehension = generátorová notace

   list comprehension = generátorová notace seznamu
   set comprehension = generátorová notace množiny
   dictionary comprehension = generátorová notace slovníku
   
Nikdy neříkej nikdy. Takže lepší nápady vítám ;)

Mějte se fajn,
   pepr


Další informace o konferenci Python