Własny zakres iterowalny

Zadanie 11 z 11 · rozdział 18Trudność: 3 z 3classiteratorgeneratoryield

Treść zadania

Zaprojektuj klasę Zakres — własny odpowiednik wbudowanej funkcji range() — po której obiektach można iterować pętlą for:

  • Konstruktor __init__(self, start, stop, krok=1) zapamiętuje parametry. Jeśli krok jest równy 0, zgłasza wyjątek ValueError("Krok nie może być równy 0.").
  • Metoda __iter__() jest generatorem — kolejne elementy zwraca instrukcją yield:
    • dla kroku dodatniego: $start, start + krok, start + 2 \cdot krok, \dots$ — dopóki element jest mniejszy od $stop$,
    • dla kroku ujemnego: $start, start + krok, \dots$ — dopóki element jest większy od $stop$.

Nie używaj w klasie wbudowanej funkcji range() — kolejne elementy wylicz samodzielnie.

Program dla każdego zapytania start stop krok tworzy obiekt Zakres i wypisuje jego elementy oraz ich sumę. Każde przejście pętlą for (a także wywołanie sum()) uruchamia generator od nowa, więc po jednym obiekcie można iterować wiele razy.

Dane wejściowe

  • 1. linia: liczba zapytań $q$
  • kolejne $q$ linii: trzy liczby całkowite start stop krok oddzielone spacjami

Dane wyjściowe

Dla każdego zapytania jedna linia:

  • <elementy oddzielone spacjami> (suma: <suma>),
  • pusty (suma: 0) — jeśli zakres nie zawiera żadnego elementu,
  • Błąd: Krok nie może być równy 0. — jeśli konstruktor zgłosił wyjątek.

Ograniczenia

  • $1 \le q \le 20$
  • $-1000 \le start, stop, krok \le 1000$

Uwagi

  • Pętla for x in obiekt: wywołuje najpierw iter(obiekt), czyli metodę obiekt.__iter__(), a potem pobiera z otrzymanego iteratora kolejne elementy.
  • Funkcja (lub metoda), która zawiera yield, jest generatorem: jej wywołanie nie wykonuje od razu kodu, tylko zwraca iterator. Każde yield „oddaje” jeden element i wstrzymuje funkcję do czasu, aż pętla poprosi o następny:
    ```python
    def odliczanie(n):
    while n > 0:
    yield n
    n -= 1
    for x in odliczanie(3):
    print(x) # 3, 2, 1 (w osobnych liniach)
    `
  • Wyjątek zgłoszony w konstruktorze przechwytuje program główny w bloku try/except (zob. zadanie „Konto bankowe”).

Przykład

Wejście
4
1 10 2
10 0 -3
5 5 1
0 5 0
Wyjście
1 3 5 7 9 (suma: 25)
10 7 4 1 (suma: 22)
pusty (suma: 0)
Błąd: Krok nie może być równy 0.
Zasady obowiązujące w rozdziale 18

Zadania w tym rozdziale uczą projektowania klas: konstruktora __init__, atrybutów, metod, metod statycznych (@staticmethod) oraz metod specjalnych, dzięki którym obiekty można wypisywać (__str__), porównywać (__eq__) i łączyć operatorami (__add__, __sub__, __mul__, …). Ostatnie zadania wprowadzają też wyjątki (raise, try/except), klasy danych (@dataclass) i generatory (yield).

Konwencje wspólne:

  • Każde zadanie to osobny program: czyta standardowe wejście i wypisuje wynik na standardowe wyjście.
  • W każdym zadaniu dostajesz kod startowy ze szkieletem klasy, a zwykle także z gotowym wczytywaniem danych i wypisywaniem wyników. Twoim zadaniem jest przede wszystkim uzupełnienie metod klasy — wynik programu zależy od tego, jak działa Twoja klasa.
  • Nazwy klas i metod podane w treści są obowiązkowe (kod startowy z nich korzysta). Nazwy w kodzie piszemy bez polskich znaków, np. Kolo, Prostokat.
  • „Z dokładnością do 2 miejsc po przecinku” oznacza dokładnie dwie cyfry po kropce, np. f"{x:.2f}" (3.00, -0.50).
  • Program nie wypisuje komunikatów typu „Podaj liczbę:”.

Zadanie pochodzi z otwartego zbioru Nauka-Programowania (z rozwiązaniami wzorcowymi). Zgłoś błąd w treści lub testach.

Python uruchomi się w przeglądarce przy pierwszym teście.

Kod zapisuje się automatycznie w tej przeglądarce. Tab wstawia wcięcie; aby opuścić edytor klawiaturą, naciśnij Esc, a potem Tab.

Testy

Program dostaje „Wejście” przez input() i musi wypisać „Oczekiwane wyjście”. Liczby porównywane są z tolerancją 0,01, a tekst podany w input("…") nie jest sprawdzany.

Test 1

Nie uruchomiono
Wejście
1
0 1 1
Oczekiwane wyjście
0 (suma: 0)

Test 2

Nie uruchomiono
Wejście
2
-5 5 5
3 -3 -2
Oczekiwane wyjście
-5 0 (suma: -5)
3 1 -1 (suma: 3)

Test 3

Nie uruchomiono
Wejście
3
1 5 -1
7 7 -1
0 -4 0
Oczekiwane wyjście
pusty (suma: 0)
pusty (suma: 0)
Błąd: Krok nie może być równy 0.

Test 4

Nie uruchomiono
Wejście
2
0 20 7
-1 -10 -4
Oczekiwane wyjście
0 7 14 (suma: 21)
-1 -5 -9 (suma: -15)

Test 5

Nie uruchomiono
Wejście
1
100 0 -25
Oczekiwane wyjście
100 75 50 25 (suma: 250)
Uruchom z własnymi danymi