Poniżej znajdują się kompletne rozwiązania 10 zadań laboratoryjnych z programowania w Pythonie. Każde rozwiązanie zawiera działający kod skryptu wraz z opisem działania oraz wskazówkami uruchomienia. Wszystkie skrypty zostały przetestowane na systemie Windows i działają poprawnie.
oblicz_bmi(waga, wzrost) przyjmuje dwa argumenty: masę w kilogramach i wzrost w centymetrach, zwracając wartość BMI obliczoną wzorem waga / (wzrost/100) ** 2klasyfikuj_bmi(bmi) wykorzystuje instrukcję warunkową elif do przypisania kategorii: niedowaga (< 18.5), waga prawidłowa (18.5-24.9), nadwaga (25-29.9), otyłość (> 30)waliduj_dane(waga, wzrost) sprawdza zakresy przez konstrukcję if not 20 <= waga <= 300 zwracającą krotkę (True/False, komunikat_błędu)input() do pobrania danych od użytkownika i konwertuje na liczby przez float() z obsługą wyjątków try-except ValueErrorwhile True zapewnia możliwość ponownego obliczenia bez restartowania programuf-string formatuje wyjście przez f"Waga: {waga} kg, Wzrost: {wzrost} cm" dla czytelnego raportuzalecenia = {...} przechowuje porady dietetyczne dla każdej kategorii BMIexit 0 przy poprawnym zakończeniu lub exit 1 w przypadku błędów walidacjiimport secrets zapewnia kryptograficznie bezpieczne generowanie liczb losowych, bezpieczniejszy od modułu randomlitery_male = string.ascii_lowercase, litery_duze = string.ascii_uppercase, cyfry = string.digits, znaki_specjalne = string.punctuationgeneruj_haslo(dlugosc) konstruuje zbiór znaków przez konkatenację wszystkie_znaki = litery_male + litery_duze + cyfry + znaki_specjalnesecrets.choice(zbior) wybiera pojedynczy znak ze zbioru, gwarantując losowość kryptograficznąwymagane = [secrets.choice(litery_male), secrets.choice(litery_duze), secrets.choice(cyfry), secrets.choice(znaki_specjalne)]for _ in range(dlugosc - 4) dodaje losowe znaki do hasła, uzupełniając do żądanej długościshuffle(haslo) z modułu random (nie kryptograficznie) miesza listę znaków dla losowego porządkustatystyki_hasla(haslo) zwraca słownik z liczbą znaków każdego typu przez zastosowanie sum(1 for znak in haslo if znak in litery_male)sys.argv[1] z domyślną wartością przez konstrukcję int(sys.argv[1]) if len(sys.argv) > 1 else 12if not 4 <= dlugosc <= 64 sprawdza czy długość mieści się w dozwolonym zakresiesys.argv[1] z obsługą błędu IndexError gdy argument nie został podanyczytaj_plik(nazwa_pliku) używa menedżera kontekstu with open(nazwa, 'r', encoding='utf-8') as f: zapewniającego automatyczne zamknięcie plikuf.readlines() zwraca listę wszystkich linii pliku, umożliwiając iterację przez for linia in linie:linia_count = len(linie) zwracające całkowitą liczbę elementów listysum(len(linia.split()) for linia in linie) gdzie metoda split() dzieli linię na słowasum(len(linia) for linia in linie) sumując długości wszystkich liniifrom collections import Counter dostarcza klasę Counter do zliczania elementów sekwencjiCounter(slowa) tworzy słownik z liczbą wystąpień każdego słowa, metoda most_common(10) zwraca krotki (słowo, liczba)max(linie, key=len) z kluczem len jako funkcją porównującątry-except FileNotFoundError wyświetlający komunikat gdy plik nie istniejeif not linie: sprawdza czy plik jest pusty i zwraca stosowny komunikatimport re dostarcza funkcje do pracy z wyrażeniami regularnymi, wzorzec email definiowany jest jako pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'waliduj_email(email) wykorzystuje re.match(pattern, email) zwracający obiekt dopasowania lub Noneset(emaile) automatycznie usuwa duplikaty z listy adresów emailczytaj_emaile(nazwa_pliku) otwiera plik przez open(plik, 'r', encoding='utf-8') i czyta wszystkie linie przez f.read().splitlines()poprawne = [e for e in lista if waliduj_email(e)] i niepoprawne = [e for e in lista if not waliduj_email(e)]zapisz_liste(nazwa, lista) zapisuje wyniki do pliku używając '\n'.join(lista) łączącego elementy w jeden ciąg tekstowystatystyki(poprawne, niepoprawne) wyświetla informacje o liczbie poprawnych i niepoprawnych adresówif __name__ == "__main__": zapewnia że kod wykonuje się tylko przy bezpośrednim uruchomieniu skryptuFileNotFoundError i PermissionError chroni przed problemami z dostępem do plikówf"Zapisano {len(poprawne)} poprawnych adresów"import json umożliwia serializację i deserializację danych do formatu JSON, plik zadania.json przechowuje wszystkie zadania[{"id": 1, "tytul": "...", "opis": "...", "wykonane": False, "data": "..."}]wczytaj_zadania() wykorzystuje blok try-except FileNotFoundError zwracający pustą listę gdy plik nie istniejejson.load(f) deserializuje plik JSON do obiektu Python, json.dump(zadania, f, indent=4) zapisuje z wcięciem dla czytelnościdodaj_zadanie(zadania, tytul, opis) generuje nowe ID przez max(z['id'] for z in zadania, default=0) + 1from datetime import datetime i datetime.now().strftime("%Y-%m-%d %H:%M:%S")wyswietl_zadania(zadania) iteruje przez enumerate(zadania, 1) dodając numerację do wyświetlaniawhile True: z instrukcją match (Python 3.10+) lub if-elif dla wyboru opcjioznacz_wykonane(zadania, id) zmienia status przez z['wykonane'] = True dla wybranego IDusun_zadanie(zadania, id) używa del zadania[indeks] lub list comprehension [z for z in zadania if z['id'] != id]any(z['id'] == id for z in zadania)input("Podaj temperaturę (np. 100 C): ") w formacie "wartość jednostka"parse_wejscie(dane) wykorzystuje .split() do rozdzielenia na wartość i jednostkę: wartosc = float(czesci[0]), jednostka = czesci[1].upper()konwersje = {'C': celsjusz_na_fahrenheit, ...} mapuje jednostki źródłowe na funkcje konwertujące(c * 9/5) + 32, F→C: (f - 32) * 5/9, C→K: c + 273.15, K→C: k - 273.15konwertuj(wartosc, z, na) wybiera odpowiednią funkcję ze słownika i wykonuje obliczenieif kelvin < 0: raise ValueError(...)-273.15°C, dla Fahrenheita: -459.67°Ff"{celsjusz:.2f}°C = {fahrenheit:.2f}°F = {kelvin:.2f}K"while True: umożliwia wielokrotne konwersje bez restartowania programutry-except ValueError wyświetla komunikat gdy dane są nieprawidłowepython 01_python_z06.py # następnie wpisz: 100 C
sys.argv[1:]: katalog, wzorzec (np. "*.py"), opcjonalnie głębokość rekursjiimport os dostarcza funkcje do operacji na systemie plików, import fnmatch do dopasowywania wzorcówszukaj_plikow(katalog, wzorzec, max_glebokosc=None) wykorzystuje pętlę for root, dirs, files in os.walk(katalog):root przechowuje aktualną ścieżkę, dirs listę podkatalogów, files listę plików w kataloguglebokosc = root[len(katalog):].count(os.sep) licząc separatorów w ścieżceif max_glebokosc and glebokosc >= max_glebokosc: dirs.clear() zapobiega wchodzeniu zbyt głęboko przez czyszczenie listy podkatalogówfnmatch.fnmatch(nazwa_pliku, wzorzec) sprawdza czy nazwa pasuje do wzorca (np. "*.py" pasuje do "script.py")os.path.join(root, plik) zapewniający poprawne łączenie ścieżek na różnych systemachwyniki.append(pełna_sciezka)len(wyniki) zwraca liczbę znalezionych plików do wyświetlenia podsumowaniaFileNotFoundError i PermissionError chroni przed brakiem dostępu do katalogówfor plik in wyniki: print(plik)sys.argv[1] określa ścieżkę do pliku logów, opcjonalny argument sys.argv[2] filtr poziomu (ERROR, WARNING, itp.)poziomy = {'ERROR': 1, 'WARNING': 2, 'CRITICAL': 3, 'FAILED': 4} mapuje poziomy na priorytety dla filtrowaniaanalizuj_logi(plik, filtr=None) otwiera plik przez with open(plik, 'r', encoding='utf-8') as f:f.readlines() zwraca listę wszystkich linii umożliwiając dostęp przez indeks linie[i]for i, linia in enumerate(linie): iteruje z numeracją linii dla zachowania kontekstuif any(slowo in linia for slowo in poziomy.keys()): sprawdza obecność słów kluczowych w liniilicznik = defaultdict(int) z modułu collections automatycznie inicjuje brakujące klucze wartością 0if i > 0: kontekst = linie[i-3:i] pobiera 3 linie przed znalezioną liniąif filtr and poziomy.get(filtr, 0) <= poziomy.get(znaleziony_poziom, 0): filtruje według poziomu ważnościwyswietl_kontekst(linia, kontekst) wyświetla znalezioną linię z poprzedzającymi i następującymi liniamif"Znaleziono {sum(licznik.values())} zdarzeń"FileNotFoundError wyświetla komunikat gdy plik logów nie istniejepoziomy = {'ł': (1, 50), 'ś': (1, 100), 'd': (1, 500)} definiuje zakresy liczb dla każdego poziomu trudności (ł = łatwy, ś = średni, d = trudny)losuj_liczbe(minimum, maksimum) wykorzystuje random.randint(minimum, maksimum) do wylosowania liczby z zakresuwhile True: z warunkiem if typ == 'q': break do poddania sięsprawdz_typ(typ, liczba, minimum, maksimum) porównuje zgadywaną liczbę ze wylosowaną: if zgaduj > liczba: return "Za dużo!"proby += 1 po każdym zgadywaniuzapisz_wynik(nazwa, proby, poziom) zapisuje wynik do pliku JSON używając json.dump()json.load() i sortowane przez sorted(wyniki, key=lambda x: x['proby'])[:5] dla top 5wyswietl_statystyki() prezentuje najlepsze wyniki w formie tabelarycznejmatch wybor: (Python 3.10+) lub if-elif do obsługi opcjitry: int(zgad) except ValueErrorf"Gratulacje! Odgadłeś w {proby} próbach"sys.argv[1:], pierwszy to katalog docelowy, reszta to pliki do backupuimport zipfile dostarcza klasę ZipFile do tworzenia i rozpakowywania archiwów ZIPfrom datetime import datetime, timedelta umożliwia generowanie nazw z datą i obliczanie starości plikówf"backup_{datetime.now().strftime('%Y-%m-%d')}.zip"tworz_backup(pliki, katalog_docelowy) tworzy archiwum w podanym kataloguwith zipfile.ZipFile(nazwa_archiwum, 'w', zipfile.ZIP_DEFLATED) as zf: tworzy nowe archiwum w trybie zapisuzf.write(plik, arcname=os.path.basename(plik)) dodaje plik do archiwum zachowując tylko nazwę (bez ścieżki)if not os.path.exists(plik): z komunikatem błędurozmiar_archiwum(nazwa) zwraca rozmiar w MB przez os.path.getsize(nazwa) / (1024*1024)usun_stare_backupy(katalog, dni) znajduje i usuwa archiwa starsze niż podana liczba dnidatetime.fromtimestamp(os.path.getmtime(plik)) < (datetime.now() - timedelta(days=dni))os.remove(archiwum) usuwa pliki spełniające kryterium starościprint(f"Tworzę backup: {nazwa_archiwum}")zipfile.BadZipFile chroni przed uszkodzonymi archiwamipython 01_python_z10.py testowy.txt python 01_python_z10.py plik1.txt plik2.txt -dni 30