<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl">
	<id>http://brain.fuw.edu.pl/edu/index.php?action=history&amp;feed=atom&amp;title=%2FCw4</id>
	<title>/Cw4 - Historia wersji</title>
	<link rel="self" type="application/atom+xml" href="http://brain.fuw.edu.pl/edu/index.php?action=history&amp;feed=atom&amp;title=%2FCw4"/>
	<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=/Cw4&amp;action=history"/>
	<updated>2026-04-18T15:56:29Z</updated>
	<subtitle>Historia wersji tej strony wiki</subtitle>
	<generator>MediaWiki 1.34.1</generator>
	<entry>
		<id>http://brain.fuw.edu.pl/edu/index.php?title=/Cw4&amp;diff=2044&amp;oldid=prev</id>
		<title>Jarekz: Utworzono nową stronę &quot;= TI:WTBD/Ćwiczenia 4 =  == iteracja i generatory == W wielkim uproszczeniu: ''generator'' to obiekt iterowalny, tzn. taki, który można umieścić w pętli ''for'...&quot;</title>
		<link rel="alternate" type="text/html" href="http://brain.fuw.edu.pl/edu/index.php?title=/Cw4&amp;diff=2044&amp;oldid=prev"/>
		<updated>2015-05-23T14:57:41Z</updated>

		<summary type="html">&lt;p&gt;Utworzono nową stronę &amp;quot;= &lt;a href=&quot;/edu/index.php/TI:WTBD&quot; title=&quot;TI:WTBD&quot;&gt;TI:WTBD&lt;/a&gt;/Ćwiczenia 4 =  == iteracja i generatory == W wielkim uproszczeniu: &amp;#039;&amp;#039;generator&amp;#039;&amp;#039; to obiekt iterowalny, tzn. taki, który można umieścić w pętli &amp;#039;&amp;#039;for&amp;#039;...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nowa strona&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= [[TI:WTBD]]/Ćwiczenia 4 =&lt;br /&gt;
&lt;br /&gt;
== iteracja i generatory ==&lt;br /&gt;
W wielkim uproszczeniu: ''generator'' to obiekt iterowalny, tzn. taki, który można umieścić w pętli ''for'' na miejscu sekwencji, po której elementach iterujemy; ale w odróżnieniu od sekwencji (listy, krotki, napisy) nie ,,zawiera&amp;quot; on ,,od razu&amp;quot; swoich elementów, tylko ,,produkuje je w miarę potrzeby&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
Przykładem generatora jest plik otwarty do odczytu; tu ,,produkowanie&amp;quot; kolejnych elementów w iteracji polega na ,,podawaniu&amp;quot; kolejnych linijek pliku, wczytanych z dysku. Co istotne: '''nie ma tu konieczności, by cała treść pliku na raz zmieściła się w pamięci operacyjnej''' -- oczywiście o ile przetwarzanie będzie miało charakter ,,lokalny&amp;quot;, bez potrzeby gromadzenia kolejnych wczytanych linijek.&lt;br /&gt;
&lt;br /&gt;
Generatory można też tworzyć samemu. Najprostsza definicja generatora wygląda całkiem jak definicja funkcji, tyle że zamiast słówka ''return'' występuje w niej słówko ''yield'' (można je przełożyć na polski jako ''ustąp''). To podobieństwo do definicji funkcji może być mylące! bo generator działa jednak dość odmiennie od funkcji. W momencie wywołania, kod generatora nie jest jeszcze uruchamiany -- zamiast tego, zwracany jest obiekt, w którym zawarty jest ten kod oraz aktualny stan generatora (wartości zmiennych lokalnych). W każdym kroku iteracji -- zrealizowanym wewnętrznie jako wywołanie metody ''next()'' generatora, kod definicji generatora jest uruchamiany, gdy jego przebieg napotka instrukcję ''yield'', wykonanie zostaje zatrzymane (z zapamiętaniem stanu i pozycji w kodzie), a argument instrukcji ''yield'' jest zwrócony jako wynik wywołania ''next()''. Kolejny krok iteracji wznowi kod generatora od linijki kolejne po ''yield'', z zachowaniem jego stanu.&lt;br /&gt;
&lt;br /&gt;
Najprostszy przykład:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def count():&lt;br /&gt;
    k = 0&lt;br /&gt;
    while True:&lt;br /&gt;
        yield k&lt;br /&gt;
        k += 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ten generator będzie wypluwał kolejne liczby naturalne (od zera począwszy) '''bez końca''' (tzn. dopóki nie zabraknie RAM-u). ''Tak zachowuje się generator, który nigdy nie powraca'' -- nigdy nie trafia się na instrukcję ''return'' (bo np. w definicji jej nie ma), ale również nie ma możliwości ,,wypadnięcia&amp;quot; za koniec kodu generatora (tu: bo nie ma wyjścia z pętli ''while''). Można lekko zmienić ten przykład:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def counter(n):&lt;br /&gt;
    k = 0&lt;br /&gt;
    while k &amp;lt; n:&lt;br /&gt;
        yield k&lt;br /&gt;
        k += 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
i teraz generator zachowuje się w iteracji jak ''range(n)'' -- iteracja kończy się na ''n''-tym elemencie (dokładnie: rzucany jest wyjątek ''StopIteration'').&lt;br /&gt;
&lt;br /&gt;
Drugi sposób stworzenia generatora polega na przekształceniu już istniejącego generatora (lub innego obiektu iterowalnego), za pomocą tzw. ''wyrażenia generatorowego''. Przykład:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
kwadraty = (k*k for k in counter())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Generator ''kwadraty'' będzie produkował po kolei kwadraty kolejnych liczb naturalnych -- bez końca, o ile ''counter()'' się nie wyczerpie (zakładamy, że dany jest definicją powyżej, a więc się nie wyczerpie). Nawiasy w wyrażeniu generatorowym są wymagane. Można je napisać równoważnie:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def kwadraty():&lt;br /&gt;
    for k in counter():&lt;br /&gt;
        yield k*k&lt;br /&gt;
kwadraty = kwadraty()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
ale wyrażenie generatorowe pozwala na prostszy zapis.&lt;br /&gt;
Ogólniejsza postać:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
kwadraty_nieparzyste = (k*k for k in counter() if k % 2)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
(zwracać kwadraty tylko tych ''k'', których dzielenie przez 2 daje niezerową resztę). Elementy podawane w iteracji przez wyrażenie generatorowe można więc opcjonalnie ''filtrować'' za pomocą warunku (wyrażenia logicznego) napisanego po słowie ''if''.&lt;br /&gt;
&lt;br /&gt;
== zadanie: numerowanie linii ==&lt;br /&gt;
Napisać program częściowo realizujący funkcję systemowego polecenia ''nl'' (p. ''man nl''), czyli numerujący linijki pliku/plików wejściowych. Zakładamy dodatkowo, że treść każdego z plików wejściowych będzie na wyjściu poprzedzona 1-linijkowym nagłówkiem z nazwą tego pliku, a wynik zostanie posłany na ''stdout''.&lt;br /&gt;
&lt;br /&gt;
Wersja pierwsza:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
# coding: utf-8&lt;br /&gt;
&lt;br /&gt;
import fileinput, sys&lt;br /&gt;
&lt;br /&gt;
header = '\n*** FILE: {} ***\n'&lt;br /&gt;
separator = ': '&lt;br /&gt;
linenumber = 0&lt;br /&gt;
&lt;br /&gt;
for line in fileinput.input():&lt;br /&gt;
    if fileinput.isfirstline():&lt;br /&gt;
        linenumber = 0&lt;br /&gt;
        sys.stdout.write(header.format(fileinput.filename()))&lt;br /&gt;
    linenumber += 1&lt;br /&gt;
#    sys.stdout.write(separator.join(str(linenumber), line)&lt;br /&gt;
#    sys.stdout.write('%d%s%s' % (linenumber, separator,line))&lt;br /&gt;
#    sys.stdout.write(str(linenumber) + separator + line)&lt;br /&gt;
    sys.stdout.write('{0}{1}{2}'.format(linenumber, separator, line))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Nic tu nie ma odkrywczego, można powiedzieć, że to proste ćwiczenie na zastosowanie modułu ''fileinput''. Linijki zakomentowane na końcu to alternatywne (równie dobre) realizacje ostatniej linijki.&lt;br /&gt;
&lt;br /&gt;
Wersja druga:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
# coding: utf-8&lt;br /&gt;
&lt;br /&gt;
def numeruj(lines, separator=': '):&lt;br /&gt;
    linenumber = 0&lt;br /&gt;
    for line in lines:&lt;br /&gt;
        linenumber += 1&lt;br /&gt;
        yield '{0}{1}{2}'.format(linenumber, separator, line)&lt;br /&gt;
&lt;br /&gt;
#inna implementacja:&lt;br /&gt;
#def numeruj(lines, separator=': '):&lt;br /&gt;
    #from itertools import count, izip&lt;br /&gt;
    #for line in izip(str(count(start=1)), lines):&lt;br /&gt;
        #yield separator.join(line)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    from sys import stdout&lt;br /&gt;
    from optparse import OptionParser&lt;br /&gt;
    from itertools import chain&lt;br /&gt;
    &lt;br /&gt;
    parser = OptionParser()&lt;br /&gt;
    parser.add_option('-H', '--header', dest='header')&lt;br /&gt;
    parser.add_option('-S', '--separator', dest='separator')&lt;br /&gt;
    opts, args = parser.parse_args()&lt;br /&gt;
    header = opts.header or '\n*** {} ***\n'&lt;br /&gt;
    separator = opts.separator or ': '&lt;br /&gt;
&lt;br /&gt;
    files = (chain(&lt;br /&gt;
                (header.format(filename),)&lt;br /&gt;
                , numeruj(open(filename), separator)&lt;br /&gt;
                )&lt;br /&gt;
                for filename in args&lt;br /&gt;
            )&lt;br /&gt;
    output = chain.from_iterable(files)&lt;br /&gt;
    &lt;br /&gt;
    for line in output:&lt;br /&gt;
        stdout.write(line)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ta wersja wygląda na nieco długą, ale to dlatego, że zrezygnowałem tu z ''fileinput'', oraz pozwoliłem by przy wywołaniu można było podać własne definicje nagłówka pliku i separatora numeru linii jako wartości opcji. Za to główne zadanie numerowania linijek zrealizowałem za pomocą ''generatora'' (definicja ''numeruj'', w dwóch wersjach). Jest to też dobra okazja, by sobie przeczytać opis wykorzystanych tu funkcji do operowania na generatorach (ogólniej -- obiektach iterowalnych), w dokumentacji modułu ''itertools''.&lt;br /&gt;
&lt;br /&gt;
== sortowanie danych ==&lt;br /&gt;
po zawartości określonego pola: częściowa emulacja polecenia systemowego ''sort''; ewentualnie z wykorzystaniem modułu ''csv'' (zadanie dla czytelnika).&lt;br /&gt;
&lt;br /&gt;
Naturalnie, sortowanie jest operacją nielokalną -- nie można ustalić, który element będzie pierwszy, zanim się nie zbadało wszystkich, więc trzymanie wszystkich elementów sortowanego zbioru na raz w pamięci jest nieuniknione. Chyba, żeby się uciec do sprytnego wykorzystania plików tymczasowych (systemowe polecenie ''sort'' tak potrafi, my tu nie będziemy próbować).&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
# coding: utf-8&lt;br /&gt;
&lt;br /&gt;
from optparse import OptionParser&lt;br /&gt;
from fileinput import input&lt;br /&gt;
&lt;br /&gt;
parser = OptionParser()&lt;br /&gt;
parser.add_option('-t', '--field-separator', dest='separator', default=None)&lt;br /&gt;
parser.add_option('-k', '--key', dest='sortfield', type='int', default=1)&lt;br /&gt;
parser.add_option('-r', '--reverse', action='store_true', dest='reverse', default=False)&lt;br /&gt;
parser.add_option('-n', '--numeric', action='store_true', dest='numeric', default=False)&lt;br /&gt;
opts, args = parser.parse_args()&lt;br /&gt;
sep, fnum, reverse, numeric = opts.separator, opts.sortfield, opts.reverse, opts.numeric&lt;br /&gt;
&lt;br /&gt;
def keyfun(l):&lt;br /&gt;
    try:&lt;br /&gt;
        r = l.split(sep)[fnum - 1] # `sort' numeruje pola od 1, a python listy - od 0 &lt;br /&gt;
    except IndexError:&lt;br /&gt;
        return None # rekord może nie mieć tylu pól, nie chcę by program wtedy padł&lt;br /&gt;
    if numeric:&lt;br /&gt;
        r = float(r)&lt;br /&gt;
    return r&lt;br /&gt;
# w następnej linii odbywa się cała faktyczna robota&lt;br /&gt;
# NB. tu generator ulega konwersji do listy (via sorted())&lt;br /&gt;
# czyli zostaje `skonsumowany'&lt;br /&gt;
lines = sorted((l.rstrip() for l in input(args)), key=keyfun, reverse=reverse)&lt;br /&gt;
for line in lines:&lt;br /&gt;
    print line&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ilustrujemy tu wykorzystanie własnej funkcji do produkcji klucza sortowania.&lt;br /&gt;
Wywołanie ''l.rstrip()'' służy temu, by każdą linijkę ,,oczyścić&amp;quot; z kodu '\n' ją kończącego (przy okazji giną też ew. spacje na końcach linii -- zakładamy, że są one bez znaczenia), inaczej użycie 'print' dałoby w sumie '\n\n' na końcu każdej linii, czyli podwójny odstęp. Jak osiągnąć to samo inaczej?&lt;br /&gt;
&lt;br /&gt;
== sortowanie strumienia danych wg. długości rekordów (linijek) ==&lt;br /&gt;
proszę wykonać samemu.&lt;br /&gt;
&lt;br /&gt;
Warto przejrzeć: http://www.dabeaz.com/generators-uk/&lt;/div&gt;</summary>
		<author><name>Jarekz</name></author>
		
	</entry>
</feed>