[python] generatorovy vyraz

Přikryl Petr prikryl na atlas.cz
Středa Březen 24 16:33:49 CET 2010



>---------------------------------------------------------
>Od: David Rohleder
>>   g = (i*i for i in range(4))
>> 
>> Jde jen o specialitu, aby překladač poznal,
>> že to je generátorový výraz. Je to jako numerický
>> výraz -- taky se může zapsat do závorek.
>
>Mně vadí nekonzistence:
>
>jde napsat 
>
>a = fce(generátor)
>
>nebo
>
>a = fce((generátor))

To i*i for i in range(4) není generátor, ale generátorový výraz.
Generátor se z toho stane až po tom přiřazení.

>je možné napsat
>
>a = (generátor)
>
>ale ne 
>
>a = generátor

Tedy přesněji, nelze napsat:

a = generátorový výraz

... jde o to, že se bez těch závorek jednoznačně 
nepozná, že jde o generátorový výraz -- podobně jako 
když se u složitějších aritmetických výrazů musí
uzávorkovat podvýrazy, protože ty podvýrazy se 
nepoznají samy od sebe.

>výmluvy na to, že by překladač nepoznal, že se jedná o generátor a ne o
>přiřazení i*i jsou liché, protože on to musí poznat např. u té funkce.
>pokud by byl tak hloupý, jak říkáš, tak by 
>
>a = fce(i*i for i in range(4))
>
>nahlásila taky syntax error jako v příkladu níže.

Jde o to, že při volání funkce překladač očekává výraz(y).
Tam není jiná možnost, že by se to dalo chápat jako příkazy.

Překladač tu situaci bez závorek samozřejmě pozná, 
ale bez těch závorek se nedá jednoznačně rozhodnout, 
jestli je to generátorový výraz nebo chybně zapsaný příkaz.

>podle mne tady tyto problémy způsobuje třeba i použití kulatých závorek,
>protože se pak jednoduše splete s nějakým tuple, případně dalšími
>operátory. Překladač musí zjišťovat jestli se ve výrazu někde vepředu
>nevyskytuje for, aby celý výraz mohl prohlásit za generátor.

Překladač se neplete. Tuple takto definovat nelze. A asi právě proto
neexistuje něco, čemu by se říkalo "tuple comprehension".
Proč by taky mělo, když to nepotřebuji a jednoduše dosadím
generátorový výraz do tuple() -- je tam o "tuple" víc a mám totéž.

>Kdybych chtěl nějakou jednoznačnou syntaxi, tak bych mnohem radši použil
>složené závorky:
>
>a = { i*i | for i in range(4)}

Jenže tohle je v Pythonu už použito (až na tu sviskou čáru, 
která je tam jaksi nepythonovsky navíc). Následující příklad
ukazuje generátor množiny (ve smyslu vytvoření vygenerované
množiny; něco jako konstruktor množiny definované 
generátorovým výrazem -- anglicky set comprehension):

>>> a = { i*i for i in range(4) }
>>> a
{0, 1, 4, 9}
>>> type(a)
<class 'set'>

A další příklad je něco podobného -- dictionary comprehension
aneb konstruktor generovaného slovníku:

>>> a = { i:i*i for i in range(4) }
>>> a
{0: 0, 1: 1, 2: 4, 3: 9}
>>> type(a)
<class 'dict'>

>> Jde taky o to, že generátorový výraz lze napsat
>> na víc řádků. Tady je jiný výraz a je to pitomost,
>> ale pro ilustraci:
>>
>> >>> g = (i*i
>> ...        for i in range(4)
>> ...        if i > 2)
>
>to už je hodně přitažené za vlasy, normálně se jeden příkaz píše na
>jeden řádek, lambda funkci taky nemůžeš napsat takovým způsobem na dva
>řádky. Tady prostě normálně funguje \ a dostaneš stejnou věc.

Jako přitažené za vlasy se to může zdát do doby, než zjistíš,
že generátorové výrazy lze do sebe zanořovat.

A taky je lepší nevydávat vlastní přání za skutečnost.
Python je rozumnější jazyk, než například makrojazyk v C.
Zpětné lomítko pro indikaci pokračovacího řádku není nutné
psát. Jinými slovy, jeden příkaz nemusí být zapsaný na
jednom řádku -- i když se nepoužije zpětné lomítko. 
Například volání funkce:

>>> def f(a, b, c, d):
...     print(a, b, c, d)
...
>>>
>>> f('první',
...   'druhý',
...   3,
...   4)
první druhý 3 4
>>>

Lambda funkce v Pythonu přestává být přirozeným
prvkem. Ve specializovaných jazycích by to bylo taky
na mašlu, kdyby se lambda výraz nemohl zalomit na víc
řádků.

Když to shrnu, tak všechny ty komplikace, které
by vznikly při jiném přístupu ke generátorovému
výrazu, nestojí za to. Navíc v situaci, která se 
prakticky vůbec nevyskytuje a ve které navíc stačí
prostě uzavřít generátorový výraz do kulatých závorek.

pepr


Další informace o konferenci Python