Python dla początkujących: nauka programowania na rodzinnych projektach

Python warto zacząć od małego programu, który coś oblicza, pyta o odpowiedź albo losuje pomysł na wspólną zabawę. Na pierwsze tygodnie wystarczy zwykły komputer, interpreter Python 3 i prosty edytor. Nie trzeba kupować kursu, konfigurować serwera ani znać całej matematyki szkolnej. Potrzebna jest natomiast gotowość do czytania komunikatów i sprawdzania, dlaczego wynik różni się od oczekiwanego. W programowaniu poprawianie własnych pomyłek jest normalną częścią pracy.

Ten poradnik prowadzi od pierwszego pliku do trzech niewielkich projektów: kalkulatora materiałów, losownika zadań i quizu. Przykłady celowo nie korzystają z kont internetowych ani dodatkowych pakietów. Można je uruchamiać lokalnie i zmieniać bez podawania danych rodzinnych. Najważniejsze jest rozumienie zależności między danymi, instrukcją i wynikiem, a nie szybkie przepisywanie kolejnych ekranów kodu. Dorosły i dziecko mogą pracować razem nawet wtedy, gdy obie osoby dopiero poznają język.

Do czego przydaje się Python w pierwszych własnych projektach

Python jest językiem programowania ogólnego przeznaczenia. W domowej nauce można wykorzystać go do obliczeń, porządkowania niewielkich zestawów danych, prostych gier tekstowych i rysowania. Nie każdy pierwszy projekt musi mieć okna, przyciski i efektowną grafikę. Program, który poprawnie wylicza liczbę potrzebnych kartek albo sprawdza odpowiedź w quizie, pozwala zobaczyć podstawową zasadę: komputer wykonuje dokładnie opisaną procedurę na przekazanych mu danych.

Warto odróżnić język od aplikacji, w której wpisujemy kod. Python określa składnię i zasady wykonywania programu, a edytor pomaga przygotować tekst pliku. Interpreter uruchamia zapisane instrukcje. Jeżeli ktoś nie rozumie tej różnicy, łatwo uznaje problem edytora za błąd języka albo szuka wyniku w oknie, które służy wyłącznie do pisania. Na początku dobrze wskazać każdą część używanego zestawu i jej konkretną funkcję.

Dobry pierwszy cel ma jedno zdanie opisu i sprawdzalny rezultat. Przykładowo program pyta o liczbę uczestników oraz liczbę kartek na osobę, a następnie oblicza łączny zapas. Takie zadanie jest lepsze od obietnicy stworzenia od razu wielkiej gry. Łatwo przygotować dane próbne i samodzielnie policzyć wynik, więc można sprawdzić poprawność bez zaawansowanej wiedzy. Później projekt da się rozbudować o rezerwę materiałów lub kilka rodzajów produktów.

Nie trzeba rozstrzygać, od jakiego wieku każdy powinien uczyć się Pythona. Ważniejsza jest gotowość konkretnej osoby do czytania krótkich instrukcji, korzystania z klawiatury i spokojnego śledzenia błędu. Młodsze dziecko może proponować przykłady, a dorosły zapisywać kod; starsze samodzielnie eksperymentować. Jeśli składnia odbiera całą przyjemność, warto zmniejszyć projekt lub wrócić do narzędzia wizualnego, zamiast traktować przerwę jako dowód braku zdolności.

Python 3 i przygotowanie środowiska bez zbędnych dodatków

Do przykładów potrzebny jest Python 3. Instalację należy pobrać z oficjalnej dystrybucji przeznaczonej dla własnego systemu, korzystając z pomocy dorosłego zarządzającego komputerem. Sposób instalowania w Windows zmienia się wraz z rozwojem oficjalnych narzędzi, dlatego nie warto kierować się starym filmem pokazującym inne okna. Najważniejszy rezultat to możliwość uruchomienia interpretera i edytora, nie odtworzenie identycznej kolejności przycisków z konkretnego nagrania.

Na początek wygodne jest IDLE, czyli środowisko zawierające interaktywną konsolę oraz edytor plików. Nie każda dystrybucja instaluje ten opcjonalny składnik identycznie, więc brak ikony nie oznacza, że cały Python nie działa. W standardowym zestawie można odszukać IDLE w aplikacjach lub dokumentacji instalacji. Zaawansowany edytor z wieloma rozszerzeniami nie jest konieczny do pierwszych ćwiczeń, a jego konfiguracja mogłaby przesłonić właściwy temat nauki.

W systemowym terminalu polecenie python --version lub dostępne w danej instalacji python3 --version pokazuje wersję interpretera; w Windows może działać również polecenie py --version. Nie należy wpisywać ich do pliku programu jako instrukcji Pythona. To polecenia uruchamiane przez system. Jeśli pojawia się komunikat, że polecenia nie znaleziono, należy sprawdzić instalację i dokumentację własnego środowiska, zamiast pobierać losowy program obiecujący naprawę wszystkich błędów.

Dobrze przygotować jeden folder, na przykład python-rodzinne-projekty, i przechowywać w nim pliki ćwiczeń. Pierwsze przykłady nie wymagają instalowania bibliotek z internetu, podawania tokenów ani dostępu administratora do zwykłego uruchomienia kodu. Nie warto także modyfikować systemowego Pythona dostarczonego z innym oprogramowaniem. Środowisko do nauki powinno być rozpoznawalne i możliwe do uporządkowania, a nie przypadkowo połączone z narzędziami, od których zależy działanie komputera.

Konsola i plik programu to dwa różne miejsca pracy

W konsoli Pythona znak >>> oznacza gotowość do przyjęcia instrukcji. Można wpisać działanie 7 * 4 i po zatwierdzeniu zobaczyć wynik 28. To dobry sposób na krótkie eksperymenty. Nie należy kopiować samego znaku zachęty do pliku programu. Jest elementem okna konsoli, podobnie jak informacja o wersji widoczna po uruchomieniu, a nie częścią kodu, którą interpreter ma później wykonywać.

Plik programu służy do zachowania kilku instrukcji i uruchamiania ich ponownie. W IDLE wybiera się File, a następnie New File, wpisuje kod i zapisuje plik z rozszerzeniem .py. Pozycja Run Module z menu Run uruchamia zawartość; standardowy skrót to F5. Wynik pojawia się w oknie Shell. Gdy zmieniamy tekst, trzeba uruchomić aktualną zapisaną wersję, zamiast oczekiwać, że wcześniejszy wynik sam się zmodyfikuje.

W pierwszym pliku wystarczy poniższa instrukcja. Po jej uruchomieniu powinien pojawić się jeden wiersz tekstu. Cudzysłowy wyznaczają napis, a nawiasy obejmują argument przekazany funkcji print. Można zmienić treść na własne powitanie i uruchomić plik ponownie. Jeżeli nic się nie wyświetla, warto sprawdzić właściwe okno wyniku i to, czy wykonano plik, który aktualnie jest otwarty w edytorze.

print("Zaczynamy rodzinny projekt.")

Nazwę pliku dobrze dopasować do zadania, na przykład powitanie.py, bez nazywania go tak samo jak używany moduł standardowy. Plik random.py mógłby później przeszkadzać w importowaniu modułu o tej nazwie z biblioteki Pythona. To drobna zasada organizacyjna o bardzo praktycznym znaczeniu. Warto też sprawdzić rozszerzenie: plik nazwany faktycznie powitanie.py.txt pozostaje zwykłym dokumentem tekstowym, mimo że jego nazwa na pierwszy rzut oka wygląda poprawnie.

Liczby, działania i kolejność obliczeń

Python może działać jak kalkulator. Dodawanie zapisuje się znakiem plus, odejmowanie minusem, mnożenie gwiazdką, a dzielenie ukośnikiem. Nawiasy pozwalają ustalić kolejność, tak jak w szkolnych działaniach. Do wyniku w pliku trzeba użyć print, ponieważ samo wyrażenie zapisane w edytorze nie musi zostać wyświetlone. To częsta różnica między doświadczeniem z konsoli a pierwszą próbą uruchomienia kilku instrukcji zapisanych w osobnym dokumencie.

Przykład z materiałami można policzyć na dwa sposoby. Działanie 4 * 3 + 2 daje czternaście, natomiast 4 * (3 + 2) dwadzieścia. Pierwsze może oznaczać cztery osoby po trzy kartki i dwie zapasowe dla całej grupy. Drugie oznacza cztery osoby po pięć kartek. Program nie odgadnie, który zamiar mieli autorzy. Poprawny znak i nawias wynikają z opisu zadania, dlatego warto najpierw nazwać sposób liczenia.

Liczby z częścią ułamkową zapisuje się w kodzie kropką, na przykład 1.5, a nie przecinkiem. Dzielenie / daje wynik zmiennoprzecinkowy, a // wykonuje dzielenie z zaokrągleniem w dół. Dla dodatnich ilości 17 // 5 daje trzy pełne grupy, natomiast 17 % 5 pokazuje resztę dwa. Przy wartościach ujemnych nie należy utożsamiać zaokrąglenia w dół z prostym odcięciem cyfr po separatorze.

Na początku warto stosować liczby całkowite, gdy opisują sztuki, minuty lub punkty. Daje to czytelne wyniki i pozwala uniknąć nieporozumień związanych z przybliżeniami liczb zmiennoprzecinkowych. Nie każdy wynik z wieloma cyframi po kropce oznacza błąd samego obliczenia. Jeśli później pojawi się projekt finansowy, trzeba osobno dobrać sposób reprezentowania kwot. Zwykły szkolny kalkulator materiałów nie powinien być bez sprawdzenia traktowany jako gotowe narzędzie do rozliczeń.

Zmienne i nazwy, które wyjaśniają zadanie

Zmienna wiąże nazwę z wartością. Instrukcja osoby = 4 pozwala później używać czytelnej nazwy zamiast powtarzać tę samą liczbę w kilku miejscach. Znak równości jest tu przypisaniem, a nie pytaniem o równość dwóch wartości. Po zmianie liczby osób trzeba ponownie wykonać obliczenie wyniku. Program nie jest automatycznie działającym arkuszem, który zawsze sam przelicza każdą wcześniejszą instrukcję po zmianie jednej zmiennej.

Dobry zestaw nazw opisuje sens danych: osoby, kartki_na_osobe, zapas i razem. Początkujący łatwiej sprawdzi wyrażenie z takimi nazwami niż z literami a, b oraz c użytymi bez objaśnienia. Podkreślenie pozwala łączyć kilka słów. Warto od początku zachowywać jedną konwencję i unikać nazw z przypadkowymi wielkimi literami, ponieważ Osoby i osoby są dla Pythona różnymi nazwami.

Poniższy program pokazuje pełne obliczenie dla czterech uczestników. Po uruchomieniu powinien wyświetlić liczbę czternaście. Można zmienić tylko osoby na sześć i przewidzieć nowy wynik przed wykonaniem pliku. Taka próba sprawdza rozumienie zależności, a nie umiejętność szybkiego przepisywania. Jeśli rezultat nie pasuje do przewidywania, warto przejść po liniach i nazwać wartość każdej zmiennej tuż przed obliczeniem.

osoby = 4
kartki_na_osobe = 3
zapas = 2
razem = osoby * kartki_na_osobe + zapas
print(razem)

Nie należy używać nazw takich jak print, input, list lub sum dla własnych danych w pierwszych ćwiczeniach. Przypisanie pod taką nazwą może zasłonić funkcję, którą program ma później wywołać. Gdy zdarzy się to w konsoli, czasem najprościej rozpocząć świeżą sesję i uruchomić poprawiony plik. Sama zmiana nazwy w edytorze nie usuwa każdej wartości, która pozostała w pamięci wcześniej używanego interpretera.

Napisy, łączenie tekstu i czytelne komunikaty

Tekst zapisuje się między zgodnymi cudzysłowami albo apostrofami. Napis "4" nie jest tym samym co liczba 4, choć na ekranie może wyglądać podobnie. Dołączenie dwóch napisów daje kolejny napis, a nie działanie arytmetyczne. Przykładowo "4" + "2" tworzy "42". To ważne przed zadaniami z pytaniem użytkownika o liczbę, ponieważ odpowiedź z klawiatury początkowo trafia do programu właśnie jako tekst.

Do prostych komunikatów przydają się f-stringi, czyli napisy poprzedzone literą f. W nawiasach klamrowych można umieścić nazwę zmiennej, na przykład print(f"Potrzeba {razem} kartek."). Wynik jest czytelny dla użytkownika i nie wymaga od niego pamiętania, co oznacza samotna liczba. Warto podawać jednostkę i sens wyniku, szczególnie gdy program wyświetla kilka różnych wielkości, które łatwo ze sobą pomylić podczas próby.

Polskie znaki mogą występować w komunikatach. Dobrze jednak odróżnić tekst dla człowieka od nazw technicznych, które będą wielokrotnie przepisywane. Nie trzeba usuwać polskich znaków z każdego zdania, ale w prostych nazwach plików i zmiennych można świadomie wybrać zapis łatwy do odtworzenia na używanej klawiaturze. Ważna jest konsekwencja. Błąd często wynika nie z obecności znaku, lecz z użycia dwóch nieco różnych zapisów w kolejnych liniach.

Jeśli tekst ma zawierać cudzysłów, można użyć drugiego rodzaju znaków na zewnątrz, na przykład print('Hasło brzmi "most".'). Nie należy wklejać ozdobnych cudzysłowów z edytora biurowego jako ograniczników kodu. Wyglądają podobnie do prostych znaków, ale interpreter nie traktuje ich identycznie. Dlatego kod warto przygotowywać w edytorze programistycznym. Dokument z automatycznym poprawianiem typografii może wprowadzać błędy, których początkujący nie zauważy podczas zwykłego czytania zdania.

Pytania do użytkownika i zamiana odpowiedzi na liczbę

Funkcja input wyświetla pytanie i czeka na odpowiedź zatwierdzoną Enterem. Wynik jest napisem, nawet jeśli użytkownik wpisał same cyfry. Aby wykonać obliczenia na liczbie całkowitej, można zastosować int. Dobrze rozdzielić te czynności na dwie linie w pierwszym ćwiczeniu. Widać wtedy, gdzie przechowywany jest tekst i w którym miejscu program próbuje nadać mu znaczenie liczby. To ułatwia późniejsze wyjaśnienie błędnej odpowiedzi.

Poniższy fragment pyta o liczbę uczestników i oblicza kartki po trzy na osobę z rezerwą dwóch sztuk. Dla odpowiedzi 4 powinien podać czternaście. Na tym etapie trzeba wpisać poprawną liczbę całkowitą. Wpisanie słowa cztery wywoła błąd konwersji, który zostanie omówiony później. Program nie rozpoznaje automatycznie wszystkich sposobów zapisu tej samej informacji; zakres dopuszczalnych odpowiedzi określa autor.

odpowiedz = input("Ile osób bierze udział? ")
osoby = int(odpowiedz)
razem = osoby * 3 + 2
print(f"Przygotuj {razem} kartek.")

Należy odróżnić brak reakcji od oczekiwania na dane. Kiedy program zatrzymał się przy input, trzeba aktywować okno Shell lub terminal i tam wpisać odpowiedź, a nie dopisywać ją do kodu w edytorze. Jeśli pytanie znika razem z oknem po dwukrotnym kliknięciu pliku, lepiej uruchamiać ćwiczenie w IDLE albo istniejącym terminalu. Dzięki temu komunikat i ewentualny błąd pozostają widoczne do spokojnego przeczytania.

Przy danych rodzinnych najlepiej korzystać z umownych przykładów. Nauka funkcji wejściowej nie wymaga podawania prawdziwego nazwiska, adresu, hasła ani numeru telefonu. Można pytać o wymyślony pseudonim albo wybrany kolor. Taki nawyk ma praktyczny sens również podczas pokazywania kodu innym osobom. Zrzut ekranu z przykładową sesją nie powinien przypadkowo ujawniać informacji, które nie są potrzebne do zrozumienia programu.

Warunki if, elif i else w praktycznej decyzji

Instrukcja if pozwala wybrać działanie zależnie od warunku. Po warunku stawia się dwukropek, a należące do niego linie otrzymują wcięcie. W typowym stylu używa się czterech spacji. else opisuje wariant przeciwny, a elif dodatkowy sprawdzany warunek. Najpierw warto przygotować zadanie z dwoma rezultatami, na przykład komunikat o wystarczającej liczbie materiałów albo o konieczności przygotowania dodatkowych sztuk dla uczestników.

W poniższym przykładzie piętnaście kartek wystarcza na dwanaście potrzebnych. Znak >= oznacza większe lub równe. Warto sprawdzić również sytuację, w której zapas jest dokładnie równy potrzebie, ponieważ to granica łatwo pomijana w nieprecyzyjnym opisie. Program podejmuje decyzję na podstawie zapisanej relacji, a nie ogólnego wyobrażenia, że materiałów jest mniej więcej dosyć. Zmiana jednego operatora może zmienić wynik właśnie na tej granicy.

kartki = 15
potrzeba = 12
if kartki >= potrzeba:
    print("Materiały są przygotowane.")
else:
    print("Trzeba dołożyć kartki.")

Do porównywania równości służy ==, natomiast pojedyncze = przypisuje wartość. Przy napisach porównanie uwzględnia ich rzeczywisty zapis, więc "Tak" i "tak" nie są identyczne. Można świadomie przekształcić odpowiedź metodą .lower() lub .casefold(), ale należy wiedzieć, po co to robimy. W pierwszym zadaniu lepiej jawnie opisać dopuszczalne odpowiedzi niż ukrywać kilka nieznanych jeszcze przekształceń wewnątrz rozbudowanego warunku.

Wcięcia są częścią znaczenia programu. Linia cofnięta do lewego marginesu przestaje należeć do poprzedniego bloku. Dlatego automatyczne wyrównanie tekstu przez zwykły edytor może zmienić działanie kodu lub spowodować błąd. Dobrą próbą jest przewidzenie, które zdania wyświetlą się dla każdego wariantu danych. Jeśli komunikat końcowy ma pojawiać się zawsze, powinien znaleźć się poza obiema gałęziami, a nie przypadkowo tylko wewnątrz else.

Pętla for i powtarzanie bez kopiowania instrukcji

Pętla for pozwala wykonać podobne działanie dla kolejnych elementów. Do prostego powtarzania przydaje się range. Wyrażenie range(1, 4) daje wartości jeden, dwa i trzy; końcowa granica cztery nie jest uwzględniona. To częsty powód pomyłki o jedną pozycję. Zamiast zapamiętywać regułę bez zastosowania, warto uruchomić krótką pętlę wypisującą numery i porównać faktyczny zestaw z przewidywaniem zapisanym wcześniej na kartce.

Przykład może przygotować podpisy trzech stanowisk rodzinnej zabawy. Zmienna numer otrzymuje kolejne wartości, a wcięta instrukcja korzysta z każdej z nich. Nie należy ręcznie zmieniać zmiennej wewnątrz tak prostej pętli, ponieważ zaciemni to pierwszy przykład. Gdy potrzebnych jest sześć stanowisk, zmienia się zakres, a nie kopiuje sześciu prawie identycznych linii. To jedna z podstawowych korzyści opisania powtarzalnego działania w programie.

for numer in range(1, 4):
    print(f"Stanowisko {numer}")

Pętla może też przechodzić po liście konkretnych nazw, co zostanie wykorzystane w quizie. Ważne, aby nie utożsamiać for wyłącznie z liczeniem. Służy również do przeglądania elementów. Na początku dobrze unikać jednoczesnego usuwania elementów z tej samej listy, po której właśnie przechodzimy. Takie zachowanie wymaga dodatkowej uwagi i nie jest potrzebne do pierwszej rodzinnej aplikacji, której celem jest po prostu odczytanie kolejnych danych.

Jeśli powtarza się tylko jedna linia zamiast planowanych trzech, trzeba sprawdzić wcięcia. Jeśli pojawia się za mało powtórzeń, warto obejrzeć granice range. W razie niejasności można dodać tymczasowy komunikat z bieżącą wartością numer. Nie jest to oszustwo ani zastępowanie rozumowania. Pokazanie stanu programu w konkretnym miejscu pomaga zobaczyć, którą drogą faktycznie wykonują się instrukcje i gdzie przewidywanie rozminęło się z rzeczywistością.

Lista: kolejność, indeks i wspólny zestaw pomysłów

Lista przechowuje kilka elementów w ustalonej kolejności. Można zapisać pomysly = ["most", "ogród", "wieża"] i korzystać z kolejnych nazw. Indeksy zaczynają się od zera, więc pomysly[0] oznacza pierwszy element. Warto od razu rozdzielić potoczne określenie pierwsza pozycja od technicznego indeksu zero. To niewielka różnica, która później pojawia się w wielu zadaniach i często wywołuje niepotrzebne zdziwienie początkujących.

Funkcja len(pomysly) zwraca liczbę elementów, a metoda append dopisuje nowy na końcu. Instrukcja pomysly.append("tunel") zmienia istniejącą listę. Nie trzeba przypisywać jej wyniku z powrotem do tej samej nazwy. Warto najpierw wyświetlić listę, wykonać dopisanie i wyświetlić ją ponownie. Takie porównanie pokazuje, co zmieniła pojedyncza instrukcja, bez ukrywania jej w dużym programie z kilkoma równoczesnymi zadaniami.

Podczas korzystania z indeksu trzeba uwzględnić długość listy. Dla trzech elementów poprawne dodatnie indeksy to zero, jeden i dwa. Próba odczytania pozycji trzy prowadzi do błędu, mimo że lista ma trzy elementy. Dlatego do zwykłego wyświetlania nazw często wygodniejsza jest pętla przechodząca bezpośrednio po zawartości niż ręczne odwoływanie się do każdej pozycji. Kod staje się krótszy i lepiej odpowiada opisowi zadania.

Rodzinny zestaw pomysłów powinien być początkowo mały i jednoznaczny. Pięć sprawdzonych nazw łatwiej przetestować niż kilkadziesiąt przypadkowych haseł. Można później dodać opis czasu, materiałów albo liczby uczestników, lecz wtedy pojawi się potrzeba lepszego uporządkowania danych. To naturalny moment poznania słownika lub kolejnej struktury. Nie warto jednak komplikować pierwszej listy tylko po to, aby program wyglądał bardziej profesjonalnie niż wynika z jego rzeczywistej funkcji.

Losowanie z modułem random bez fałszywej obietnicy sprawiedliwości

Biblioteka standardowa Pythona zawiera moduł random, którego można użyć w prostej grze lub losowniku pomysłów. Instrukcja import random udostępnia go w programie. Dla niepustej listy random.choice wybiera jeden element. Nie trzeba instalować pakietu o tej samej nazwie z internetu. Jeśli import nie działa prawidłowo, warto sprawdzić, czy własny plik nie został nazwany random.py i nie zasłania modułu dostarczonego z Pythonem.

Poniższy program losuje zadanie z trzech propozycji. Każde uruchomienie daje jeden wybór, ale ten sam pomysł może pojawić się kilka razy z rzędu. To normalne przy niezależnym losowaniu z całej listy. Nie należy ogłaszać błędu po dwóch identycznych wynikach. Jeśli celem jest rozdzielenie wszystkich zadań bez powtórek, potrzebna jest inna procedura, na przykład przetasowanie kopii listy i pobieranie kolejnych pozycji.

import random
pomysly = ["Zbuduj most", "Narysuj ogród", "Wymyśl nazwę miasta"]
wybor = random.choice(pomysly)
print(wybor)

Wersję bez powtórek można przygotować przez random.sample(pomysly, k=len(pomysly)), otrzymując nową kolejność wszystkich elementów. Potem pętla wyświetla kolejne zadania. Gdy chcemy wybrać mniej propozycji, k określa ich liczbę, ale nie może przekraczać długości dostępnej listy przy takim losowaniu. To ograniczenie warto sprawdzić jawnie, zamiast liczyć, że funkcja automatycznie uzupełni brakujące elementy albo sama zmieni zasady projektu.

Moduł random nie służy do tworzenia haseł, tokenów bezpieczeństwa ani podobnych danych. W poradniku jest narzędziem zabawy i ćwiczenia programowania. Losowanie nie rozwiązuje też rodzinnego sporu o zakres dopuszczalnych zadań. Najpierw trzeba uzgodnić listę, a dopiero potem wybierać z niej wynik. Program nie potrafi ocenić, czy zadanie jest odpowiednie dla konkretnej osoby, możliwe do wykonania w danym miejscu albo zgodne ze wspólną umową.

Funkcje: własna nazwa dla powtarzalnego obliczenia

Funkcja pozwala wydzielić zadanie i nadać mu nazwę. Definicja zaczyna się od def, potem występują nazwa, parametry w nawiasach i dwukropek. Wcięte linie tworzą ciało funkcji. Samo zdefiniowanie nie uruchamia obliczenia dla wszystkich możliwych danych. Trzeba jeszcze wywołać funkcję z konkretnymi argumentami. To rozróżnienie jest podobne do zapisania przepisu i przygotowania dania: opis działania nie oznacza, że jego rezultat już powstał.

Przykładowa funkcja liczy zapas kartek i zwraca wynik przez return. Dzięki temu rezultat można później wyświetlić, porównać albo wykorzystać w kolejnym działaniu. Nie należy mylić zwracania wartości z jej drukowaniem na ekranie. Funkcja, która tylko wyświetla liczbę, nie musi udostępniać jej w formie wygodnej do dalszych obliczeń. Na początku warto zachować jeden jasny cel i jeden wynik zamiast łączyć w funkcji wszystkie zadania naraz.

def policz_kartki(osoby, na_osobe, zapas):
    return osoby * na_osobe + zapas
wynik = policz_kartki(4, 3, 2)
print(wynik)

Ten sam fragment można wywołać dla innego zestawu: policz_kartki(6, 2, 3) powinno dać piętnaście. Dwa proste sprawdziany pomagają ocenić, czy funkcja rzeczywiście korzysta z parametrów, czy przypadkowo pozostawiono w środku liczby z pierwszego przykładu. Warto także sprawdzić zero uczestników i ustalić, jaki wynik ma wtedy sens. Program obliczy wartość według wzoru, ale znaczenie dopuszczalnych danych nadal musi określić autor.

Nazwy parametrów są lokalną częścią funkcji. Dobrze jednak nie używać od razu wielu takich samych nazw w różnych miejscach, jeśli początkujący gubi ich znaczenie. Najpierw trzeba umieć wskazać argumenty przy wywołaniu, wartości wewnątrz i miejsce odbioru wyniku. Dopiero później warto porządkować większy projekt na kilka funkcji. Samo mnożenie ich liczby nie poprawia jakości programu, jeśli nie odpowiadają wyraźnym, dającym się osobno sprawdzić zadaniom.

Słownik i uporządkowane informacje o jednym zadaniu

Słownik wiąże klucze z wartościami. Dla projektu rodzinnego można zapisać zadanie = {"nazwa": "most", "minuty": 20, "osoby": 2}. Odczyt zadanie["minuty"] daje dwadzieścia. Klucze opisują znaczenie danych, więc nie trzeba pamiętać, że druga pozycja oznacza czas, a trzecia liczbę uczestników. To wygodniejsze od listy różnorodnych informacji, której sens zależy wyłącznie od kolejności ustalonej w głowie autora.

Warto odróżnić pojedynczy słownik od listy słowników. Jeden opisuje jedno zadanie, a lista może przechowywać kilka takich opisów. Pętla przechodzi wtedy po kolejnych zadaniach i odczytuje ten sam klucz z każdego. Nie trzeba od razu tworzyć złożonej bazy danych. Kilka rekordów zapisanych w kodzie wystarczy, aby nauczyć się oddzielać zestaw informacji od instrukcji, która te informacje przegląda i przedstawia użytkownikowi.

Odwołanie do nieistniejącego klucza przez nawiasy wywoła błąd. Metoda .get pozwala świadomie podać wartość domyślną, ale nie powinna ukrywać literówek w wymaganych danych. Jeśli każde zadanie ma mieć czas, brak klucza minuty jest informacją o niekompletnym opisie. Warto go naprawić, zamiast automatycznie zastępować zerem i później dziwić się, że program proponuje wykonanie rozbudowanej pracy w czasie równym zero minut.

Przy nazwach pól dobrze stosować jeden zapis w całym projekcie. czas, minuty i czas_min mogą mieć podobny sens dla człowieka, lecz program traktuje je jako różne klucze. Mała umowa dotycząca danych zapobiega wielu błędom. Zanim pojawi się sto rekordów, warto sprawdzić trzy przykłady i upewnić się, że każdy ma tę samą strukturę. To prosta forma projektowania danych, którą można zrozumieć bez poznawania terminologii baz danych.

Błędy składni, nazwy i odczytywanie komunikatu

Komunikat błędu nie jest oceną umiejętności autora. Zwykle zawiera nazwę problemu i miejsce, w którym interpreter go zauważył. Przy SyntaxError warto sprawdzić wskazaną linię oraz poprzednią: brak zamkniętego cudzysłowu, nawiasu lub dwukropka może ujawnić się dopiero trochę dalej. Nie należy poprawiać wszystkiego naraz. Lepiej usunąć jedną zrozumiałą przyczynę i uruchomić plik ponownie, obserwując, czy komunikat rzeczywiście zniknął.

NameError często oznacza użycie nazwy, której nie zdefiniowano w danym miejscu. Może to być literówka, inna wielkość litery albo wywołanie funkcji przed wykonaniem jej definicji. Warto porównać zapis znak po znaku. TypeError wskazuje natomiast nieodpowiednie połączenie operacji i typu danych, na przykład próbę dodania liczby do tekstu. Sam wynik wyświetlany na ekranie nie zawsze pozwala odróżnić te typy, dlatego przydaje się sprawdzenie źródła wartości.

ValueError może pojawić się przy int("cztery"), ponieważ taki napis nie ma oczekiwanej postaci liczby. IndexError wiąże się między innymi z odczytem pozycji poza listą, a KeyError z brakującym kluczem słownika. Nie trzeba zapamiętywać całego katalogu wyjątków. W pierwszych projektach wystarczy powiązać kilka spotkanych nazw z własnym przykładem i wiedzieć, jaką informację należy skontrolować, zamiast reagować na każdy komunikat identycznym ponownym uruchomieniem komputera.

Do wyjaśniania działania można dodawać tymczasowe print, pokazujące wartość zmiennej przed kłopotliwą instrukcją. Jeśli program oblicza dziwny zapas, warto wyświetlić osobno liczbę uczestników, normę na osobę i rezerwę. Błąd może być logiczny i nie powodować żadnego wyjątku. Poprawny składniowo program nadal może rozwiązywać inne zadanie niż zamierzono. Dlatego potrzebny jest ręcznie sprawdzony przykład, który dostarcza wzorca poprawnego wyniku, a nie tylko brak czerwonego komunikatu.

Obsługa niepoprawnej odpowiedzi bez ukrywania każdego problemu

Program pytający użytkownika o liczbę powinien przewidywać pomyłkę. Blok try pozwala wykonać czynność, a except ValueError obsłużyć konkretny błąd zamiany tekstu na liczbę. Nie należy na początku przechwytywać wszystkich możliwych błędów i wyświetlać zawsze tego samego zdania. Taki zabieg ukryje również literówkę autora oraz rzeczywisty problem programu, utrudniając znalezienie przyczyny. Lepiej obsłużyć dokładnie ten przypadek, którego spodziewamy się po danych wejściowych.

Próba może przyjąć poniższą postać. Wpisanie słowa zamiast liczby daje czytelny komunikat, natomiast liczba jest dodatkowo sprawdzana pod względem znaku. To dwa różne rodzaje kontroli. int potwierdza, że tekst da się odczytać jako liczbę całkowitą, ale nie rozstrzyga, czy ujemna liczba uczestników ma sens. Ograniczenia wynikają z zadania i muszą być zapisane osobno, nawet jeśli konwersja technicznie się udała.

try:
    osoby = int(input("Liczba uczestników: "))
except ValueError:
    print("Wpisz liczbę całkowitą cyframi.")
else:
    if osoby < 0:
        print("Liczba uczestników nie może być ujemna.")
    else:
        print(f"Kartki: {osoby * 3 + 2}")

Nie każda rodzinna aplikacja potrzebuje od razu pętli powtarzającej pytanie do skutku. Najpierw warto poprawnie obsłużyć pojedynczą odpowiedź. Gdy to działa, można zaprojektować ponawianie i wyjście. Jeżeli pojawia się while, musi być jasne, kiedy warunek przestaje obowiązywać albo kiedy wykonuje się break. Program, który bez końca pyta o to samo i nie daje zrozumiałego zakończenia, jest mało wygodny, nawet jeśli sam rachunek pozostaje poprawny.

Komunikat powinien wyjaśniać, czego oczekuje aplikacja. Zdanie nieprawidłowe dane nie mówi, czy chodzi o litery, przecinek, wartość ujemną czy przekroczony zakres. Lepszy jest konkretny opis, na przykład wpisz liczbę całkowitą od zera do dwudziestu. Potem trzeba sprawdzić, czy program rzeczywiście stosuje taki zakres. Nie warto obiecywać ograniczenia w pytaniu, jeśli w kodzie nie ma żadnej instrukcji, która je sprawdza i reaguje na jego naruszenie.

Projekt pierwszy: kalkulator materiałów z rezerwą

Kalkulator materiałów można oprzeć na funkcji poznanej wcześniej. Najpierw ustala się dane: liczbę osób, zapotrzebowanie na osobę i rezerwę dla całej grupy. Wynik ma obejmować ich iloczyn oraz zapas. Warto przygotować dwa ręczne przykłady, na przykład cztery osoby po trzy kartki plus dwie rezerwowe dają czternaście, a sześć osób po dwie plus trzy dają piętnaście. Dopiero potem dopisuje się pytania wejściowe i czytelne komunikaty.

Funkcja obliczeniowa nie musi zawierać input. Można osobno pobrać dane, osobno je sprawdzić, a potem przekazać do policz_kartki. Takie rozdzielenie upraszcza kontrolę, ponieważ wzór da się uruchomić bez wielokrotnego wpisywania odpowiedzi z klawiatury. Jeśli wynik jest błędny, wiadomo, czy sprawdzać dane, ich konwersję czy samo działanie. To praktyczny powód organizowania programu, a nie wyłącznie zabieg poprawiający wygląd kodu w edytorze.

Rozbudowa może obejmować kilka rodzajów materiałów zapisanych w słowniku, na przykład kartki i naklejki z różnymi normami. Nie należy jednak dodawać cen, rabatów i zaokrągleń finansowych, zanim podstawowa wersja działa. Każda nowa funkcja powinna mieć własny przykład kontrolny. Jeśli rezerwę zmienia się z liczby sztuk na procent, trzeba zdefiniować sposób zaokrąglenia do pełnych przedmiotów. Sama zamiana nazwy zmiennej nie rozwiązuje tej zmiany znaczenia danych.

Gotowy projekt warto sprawdzić na zerze, małej liczbie i liczbie większej od planowanej grupy. Trzeba też ustalić, czy zero uczestników nadal uzasadnia rezerwę dwóch kartek, czy wynik powinien wtedy być zerowy. Obie decyzje mogą mieć sens w różnych zastosowaniach. Program nie wybiera właściwej polityki sam. To autor opisuje regułę, a test pokazuje, czy kod ją realizuje. Właśnie tu proste zadanie zaczyna uczyć czegoś więcej niż samego mnożenia.

Projekt drugi: losownik zadań z kontrolą powtórek

Losownik warto zacząć od pięciu umówionych propozycji, które wszystkie są możliwe do wykonania. W wersji najprostszej program wybiera jedną z listy przez random.choice. Użytkownik otrzymuje komunikat z wylosowaną nazwą. Najpierw trzeba sprawdzić, czy lista nie jest pusta, ponieważ wybór z pustego zestawu nie ma sensu. To dobry przykład, że przed wywołaniem poprawnej funkcji należy jeszcze przygotować dane spełniające jej wymagania.

Jeśli każde zadanie ma zostać wykorzystane najwyżej raz podczas danej sesji, można stworzyć przetasowaną kolejność i przechodzić po niej pętlą. Nie ma potrzeby losować bez końca i odrzucać kolejnych powtórzeń. Gdy zbiór robi się prawie wyczerpany, taki naiwny sposób traci przejrzystość. Warto od początku nazwać różnicę między niezależnym losowaniem z powtórzeniami a losowym ustaleniem kolejności całej listy, bo są to dwa odrębne zamiary użytkownika.

Rozszerzenie może przechowywać przy zadaniu przybliżony czas i liczbę potrzebnych osób. Program najpierw wybiera propozycje zgodne z zadanymi warunkami, a dopiero potem losuje spośród nich jedną. Po filtracji lista może okazać się pusta, co wymaga jasnego komunikatu, a nie losowania z nieistniejącego zestawu. Takie zadanie łączy słownik, listę, warunek i funkcję w cel, którego sens jest zrozumiały bez obszernych wyjaśnień teoretycznych.

Wynik nie powinien zastępować rozmowy o zgodzie na udział. Jeżeli zadanie wymaga materiału, którego nie ma, albo aktywności nieodpowiedniej w danym momencie, trzeba zmienić zestaw danych. Program nie ma wiedzy o całej sytuacji rodziny. Można dopisać możliwość ponownego wyboru, lecz warto ustalić, kiedy korzysta się z niej i czy poprzednia propozycja wraca do puli. Te reguły są częścią projektu, a nie drobnym szczegółem dodawanym dopiero po sporze.

Projekt trzeci: quiz z listą pytań i liczeniem punktów

Quiz może przechowywać pytania i odpowiedzi jako listę par. Każde pytanie jest pokazywane użytkownikowi, odpowiedź zostaje porównana z oczekiwaną, a licznik punktów rośnie po trafieniu. Na początek najlepiej użyć pytań o jednoznacznej krótkiej odpowiedzi. Nie warto zaczynać od oceniania całego opowiadania ani odpowiedzi zależnej od interpretacji. Prosty warunek równości tekstu nie potrafi rozsądnie ocenić takich wypowiedzi i mógłby niesprawiedliwie odrzucać poprawne warianty.

Poniższy przykład zawiera dwa pytania, lokalne dane i wynik końcowy. Metody .strip() oraz .casefold() usuwają zewnętrzne odstępy i ujednolicają wielkość liter do porównania. Nie powodują jednak, że każde podobne znaczeniowo zdanie zostanie uznane. Jeśli odpowiedź wymaga polskiego znaku, trzeba go wpisać zgodnie z przyjętą regułą albo świadomie dopuścić dodatkowy wariant. Program powinien stosować jasne kryterium, które użytkownik może poznać.

pytania = [
    ("Ile boków ma trójkąt? ", "3"),
    ("Jak nazywa się nasza planeta? ", "ziemia"),
]
punkty = 0
for tresc, poprawna in pytania:
    odpowiedz = input(tresc).strip().casefold()
    if odpowiedz == poprawna:
        punkty += 1
        print("Dobra odpowiedź.")
    else:
        print(f"Oczekiwana odpowiedź: {poprawna}")
print(f"Wynik: {punkty} z {len(pytania)}")

Najpierw trzeba sprawdzić przypadek wszystkich poprawnych odpowiedzi, potem wszystkich błędnych i mieszany zestaw. Warto też wykonać próbę z wielką literą oraz przypadkowym odstępem na końcu. To pozwala potwierdzić, że użyte przekształcenia działają zgodnie z opisem. Samo przejście programu bez awarii nie wystarcza. Licznik może zwiększać się w złej gałęzi albo nie zerować się przed nową rundą, a mimo to na ekranie pojawi się pozornie wiarygodny wynik.

Rozbudowa quizu może obejmować losowanie kolejności pytań, kilka dopuszczalnych odpowiedzi i objaśnienie po każdej próbie. Nie należy jednak przedstawiać punktów jako diagnozy wiedzy dziecka. Krótki domowy zestaw ma ograniczony zakres i może zależeć od sposobu zapisania odpowiedzi. Najciekawszą częścią nauki programowania bywa odkrycie, dlaczego program czegoś nie rozpoznał. Wtedy można poprawić dane lub regułę zamiast uznawać automatyczny wynik za niepodważalną ocenę człowieka.

Zapisywanie wyniku do pliku bez przypadkowego kasowania danych

Do prostego zapisu można użyć pliku tekstowego i instrukcji with open. Ważny jest tryb otwarcia. "w" zapisuje od początku i może nadpisać wcześniejszą zawartość, natomiast "a" dopisuje na końcu. Pierwsze ćwiczenia należy wykonywać we własnym folderze na specjalnie utworzonym pliku próbnym. Nie wolno testować zapisu na ważnych dokumentach rodzinnych, nawet jeśli przykład wygląda na bardzo krótki i nieszkodliwy.

Poniższy fragment dopisuje jeden wiersz do pliku o umówionej nazwie. Kodowanie UTF-8 pozwala zachować polskie znaki, a \n oznacza przejście do następnego wiersza. Plik powstaje względem bieżącego folderu pracy programu, który nie w każdej metodzie uruchamiania jest oczywisty. Jeśli trudno go znaleźć, należy sprawdzić ten folder, a nie wielokrotnie uruchamiać zapis i zakładać, że każde kolejne wykonanie naprawi brak widocznej ikony.

with open("wyniki-probne.txt", "a", encoding="utf-8") as plik:
    plik.write("Runda próbna: 2 punkty\n")

Po uruchomieniu warto otworzyć plik zwykłym edytorem tekstu i sprawdzić faktyczny rezultat. Drugie wykonanie powinno dopisać drugi wiersz, a nie zastąpić poprzedni. To prosty test znaczenia trybu a. Jeśli później projekt ma rozpoczynać nową historię wyników, decyzję o wyczyszczeniu trzeba podjąć świadomie. Nie warto ukrywać nadpisania w funkcji, której nazwa sugeruje jedynie dodanie nowego rezultatu do dotychczasowego zestawu danych.

Wyniki domowych ćwiczeń nie wymagają prawdziwych danych uczestników. Wystarczy numer rundy lub umowny pseudonim. Przy wspólnym komputerze trzeba też pamiętać, że zwykły plik tekstowy nie jest automatycznie prywatny ani zaszyfrowany. Jeśli program ma być później wysyłany znajomym, warto sprawdzić, czy przypadkiem nie dołączono zapisów użytkowników. Kod i dane powstające podczas jego używania są różnymi rzeczami, które należy przejrzeć osobno przed udostępnieniem całego folderu.

Jak rozwijać umiejętności bez przeskakiwania do zbyt dużej aplikacji

Po trzech projektach dobrze wrócić do jednego i poprawić konkretną funkcję. Można dodać wybór liczby pytań, lepszy komunikat błędu albo zapis wyników z nową nazwą pliku. Każda zmiana powinna mieć opis oczekiwanego działania i przykład kontrolny. Nie trzeba natychmiast przechodzić do aplikacji mobilnej czy serwisu internetowego. Mniejszy program, który autor potrafi samodzielnie wyjaśnić i poprawić, daje solidniejsze podstawy niż rozbudowany projekt złożony z nierozumianych fragmentów.

W rodzinnej pracy pomagają zmienne role. Jedna osoba opisuje oczekiwanie i dane próbne, druga wpisuje kod, a potem obie zamieniają się zadaniami. Osoba bez klawiatury nie powinna stale dyktować każdej litery. Może natomiast pytać, co wydarzy się dla zera albo błędnej odpowiedzi. Taki podział uczy rozumienia programu z dwóch stron: jako autora instrukcji oraz użytkownika, który nie zna wszystkich założeń ukrytych w głowie twórcy.

Pomoc z internetu lub narzędzia AI warto wykorzystywać do wyjaśnienia konkretnego problemu, bez wklejania poufnych danych. Otrzymany kod należy przeczytać i uruchomić na przykładzie próbnym. Nie wolno zakładać, że poprawnie brzmiące objaśnienie gwarantuje działanie. Jeśli fragment usuwa pliki, instaluje pakiety lub łączy się z usługą, wymaga osobnego zrozumienia. Pierwsze zadania z tego poradnika nie potrzebują takich działań i nie uzasadniają wykonywania nieznanych poleceń tylko dla przyspieszenia nauki.

Dobrym sprawdzianem postępu jest umiejętność opowiedzenia, skąd pochodzą dane, gdzie zapada decyzja i jak powstaje wynik. Jeśli autor potrafi zmienić jedną regułę oraz przewidzieć skutek, uczy się programowania, a nie wyłącznie odtwarzania tekstu. Warto zachować pierwsze wersje plików i krótkie notatki o poprawionych błędach. Pokazują rzeczywisty rozwój: bardziej czytelne nazwy, lepsze sprawdzanie danych i świadomy podział zadania na części, które da się osobno przetestować.