W poprzednich lekcjach, nauczyliśmy się czym jest programowanie obiektowe w Python (OOP), moduły, ale przede wszystkim nauczyliśmy się podstaw języka Python. Czas to wszystko połączyć w całość i wykonać mały, lecz ciekawy projekt / zadanie – organizer. Zaczynajmy!

Zadanie jest proste. Musimy napisać program, który będzie symulować organizer / notes / segregator. A mianowicie:

  • Musi mieć możliwość przechowywania notatek oraz wizytówek
  • Po uruchomieniu, powinno wyświetlać się menu, które pozwala użytkownikowi: (1) – dodać notatkę (2) – dodać wizytówkę (3) wyświetlić notatki (4) – wyświetlić wizytówki (0) zamknąć organizer, a tym samym zakończyć działanie programu
  • Program powinien być podzielony na moduły, czyli plik

Potencjalne rozwiązanie.

na pierwszy rzut oka, mamy 3 różne klasy:

  1. klasa organizer – która zawiera metody zarządzające jego pracą. Jak dodaj notatkę
  2. klasa notatka – zawierająca takie elementy jak tytuł oraz treść. Być może priorytet
  3. klasa wizytówka – zawierająca imię, nazwisko, telefon itd

Klasa organizer

Potencjalnie, nasza klasa mogła by mieć taką strukturę:

class organizer:

    __właściciel = ""
    __bazaDanych = []

    def __init__(self, właściciel):
        self.właściciel = właściciel

    def dodajNotatkę(self):
        pass

    def dodajWizytówkę(self):
        pass

    def wyświetlNotatki(self):
        pass

    def wyświetlWizytówki(self):
        pass

Czyli spełniała by funkcje, które są w zadaniu. zmienna ‚__bazaDanych’, jest natomiast listą, która może przechowywać obiekty typu ‚notatka’, lub ‚wizytówka’. Jak tylko zostaną dodane za pomocą funkcji dodajNotatkę(), oraz dodajWizytówkę(). A funkcje wyświetlNotatki oraz wyświetlWizytówki(), mogą czytać naszą bazę danych i drukować wybrane elementy. Ma to sens.

Klasa notatka oraz wizytówka

Obydwie klasy, mają części wspólne i wydaje się być uzasadnione, aby utworzyć klasę nadrzędną ‚przedmiot’, którą będą dziedziczyć, a która będzie dbać, że obydwie klasy, będą podobne.

W przyszłości ułatwi nam to również dodawanie kolejnych przedmiotów. Jedną z rzeczy które chcieli byśmy wymusić, to aby i ‚notatka’ i ‚wizytówka’, obsługiwały metodę specjalną __str__, która odpowiada za to, aby obiekt mógł być obsłużony funkcją print. Jak print(notatka) czy też print(wizytówka).

Będzie to wielkim ułatwieniem dla metod klasy ‚organizator’, które mają wyświetlać notatki i wizytówki. Tym samym klasy te mogą wyglądać następująco:

from abc import ABC, abstractmethod

class przedmiot(ABC):

    def __init__ (self, typ, priorytet):
        pass

    @abstractmethod
    def __str__(self):
        pass

class notatka(przedmiot):

    def __init__(self, priorytet, tytuł, treść):
        pass

    def __str__(self):
        pass

class wizytówka(przedmiot):
    
    def __init__(self, priorytet, imię, nazwisko, telefon):
        pass

    def __str__(self):
        pass

Klasa ‚notatka’ oraz ‚wizytówka’, nadpisują metodę specjalną ‚__str__’, w której musimy zdefiniować, co chcemy, aby się wyświetlało, jeżeli postanowimy wydrukować naszą klasę, za pomocą print(notatka / wizytówka).

Natomiast, w konstruktorach, trzeba zadbać o wywołanie konstruktora, klasy ‚przedmiot, oraz o zainicjowanie pozostałych zmiennych, przekazanych w parametrach.

Tym samym, nasze klasy, mogą przyjąć finalną postać:

from abc import ABC, abstractmethod

class przedmiot(ABC):

    def __init__ (self, typ, priorytet):
        self.typ = typ
        self.priorytet = priorytet

    @abstractmethod
    def __str__(self):
        pass

class notatka(przedmiot):

    def __init__(self, priorytet, tytuł, treść):
        super().__init__("notatka", priorytet)
        self.tytuł = tytuł
        self.treść = treść

    def __str__(self):
        info = self.typ + "Priorytet " + self.priorytet + "\n"
        info += self.tytuł + "\n"
        info += self.treść + "\n"
        return  info

class wizytówka(przedmiot):
    
    def __init__(self, priorytet, imię, nazwisko, telefon):
        super().__init__("wizytówka", priorytet)
        self.imię = imię
        self.nazwisko = nazwisko
        self.telefon = telefon

    def __str__(self):
        info = self.typ + "Priorytet " + self.priorytet + "\n"
        info += self.imię + " " + self.nazwisko + "\n"
        info += self.telefon + "\n"
        return  info

W kolejnym kroku, należy uzupełnić naszą klasę ‚organizer’, tak aby metody spełniały swoje zadania.

Klasa organizer.

  1. Metody ‚dodajNotatkę()’ oraz ‚dodajWizytówkę()’, muszą odpytywać użytkownika o szczegóły notatek i wizytówek, które użytkownich chce dodać, następnie tworzyć na tej podstawie obiekt i dodać go do naszej bazy danych, którą jest zmienna __bazaDanych.
  2. Metody ‚wyświetlNotatki()’ oraz ‚wyśletlWizytówki()’, muszą przeszukiwać naszą bazę danych i drukować odpowiednie obiekty.

i tym samym, nasza klasa ‚organizer’, jest gotowa przyjąć swoją finalną formę:

class organizer:

    __właściciel = ""
    __bazaDanych = []

    def __init__(self, właściciel):
        self.właściciel = właściciel

    def dodajNotatkę(self):
        priorytet = input("Priorytet:")
        tytuł = input("Tytuł:")
        treść = input("Treść:")

        nowaNotatka = notatka (priorytet, tytuł, treść)
        self.__bazaDanych.append(nowaNotatka)

    def dodajWizytówkę(self):
        priorytet = input("Priorytet:")
        imię = input("Imię:")
        nazwisko = input("Nazwisko:")
        telefon = input("Telefon:")

        nowaWizytówka = wizytówka(priorytet, imię, nazwisko, telefon)
        self.__bazaDanych.append(nowaWizytówka)

    def wyświetlNotatki(self):

        print("Lista notatek:")
        for i in self.__bazaDanych:
            if i.typ == 'notatka':
                print(i)

    def wyświetlWizytówki(self):
        
        print('Lista wizytów')
        for i in self.__bazaDanych:
            if i.typ == 'wizytówka':
                print(i)

Interakcja z użytkownikiem

Temat, który nie został przez nas jeszcze, zaadresowany, to interakcja programu z użytkownikiem i wykonywanie jego poleceń.

Do tego celu, możemy wykorzystać pętle ‚while’, w której:

  1. Drukowana jest instrukcja obsługi, prosząc użytkownika o podanie informacji o żądanej akcji
  2. W czytywać wybór użytkownika
  3. Na tej podstawie wywoływać metody obiektu ‚organizer’. Który to uczywiście musi być wcześniej utworzony.

Taka interakcja, może mieć następującą postać:

organizerAnalityka = organizer("Anality.edu.pl")

while True:

    print("""Co chcesz zrobić?:

                1- Dodać notatkę
                2- Dodać wizytówkę
                3- Wyświetlić notatki
                4- Wyświetlić wizytówki
                0- Zamknać organizer""")

    x = input()
    
    if x == '0': break 
    if x == '1': organizerAnalityka.dodajNotatkę()
    if x == '2': organizerAnalityka.dodajWizytówkę()
    if x == '3': organizerAnalityka.wyświetlNotatki()
    if x == '4': organizerAnalityka.wyświetlWizytówki()

I w tym momencie, nasz program, jest skończony z punktu widzenia funkcjonalnego. Powyższe kody można wgrać do jednego pliku i go uruchomić. My jednak mamy polecenie, aby był zbudowany w duchu modułowości Pythona, tak wiec musimy go jeszcze na te moduły podzielić.

Tym samym, mogą powstać 3 pliki, tak jak poniżej:

run.py

from organizer import organizer

organizerAnalityka = organizer("Anality.edu.pl")

while True:

    print("""Co chcesz zrobić?:

                1- Dodać notatkę
                2- Dodać wizytówkę
                3- Wyświetlić notatki
                4- Wyświetlić wizytówki
                0- Zamknać organizer""")

    x = input()
    
    if x == '0': break 
    if x == '1': organizerAnalityka.dodajNotatkę()
    if x == '2': organizerAnalityka.dodajWizytówkę()
    if x == '3': organizerAnalityka.wyświetlNotatki()
    if x == '4': organizerAnalityka.wyświetlWizytówki()

organizer.py

from przedmioty import notatka, wizytówka

class organizer:

    __właściciel = ""
    __bazaDanych = []

    def __init__(self, właściciel):
        self.właściciel = właściciel

    def dodajNotatkę(self):
        priorytet = input("Priorytet:")
        tytuł = input("Tytuł:")
        treść = input("Treść:")

        nowaNotatka = notatka (priorytet, tytuł, treść)
        self.__bazaDanych.append(nowaNotatka)

    def dodajWizytówkę(self):
        priorytet = input("Priorytet:")
        imię = input("Imię:")
        nazwisko = input("Nazwisko:")
        telefon = input("Telefon:")

        nowaWizytówka = wizytówka(priorytet, imię, nazwisko, telefon)
        self.__bazaDanych.append(nowaWizytówka)

    def wyświetlNotatki(self):

        print("Lista notatek:")
        for i in self.__bazaDanych:
            if i.typ == 'notatka':
                print(i)

    def wyświetlWizytówki(self):
        
        print('Lista wizytów')
        for i in self.__bazaDanych:
            if i.typ == 'wizytówka':
                print(i)


    

przedmioty.py

from abc import ABC, abstractmethod

class przedmiot(ABC):

    def __init__ (self, typ, priorytet):
        self.typ = typ
        self.priorytet = priorytet

    @abstractmethod
    def __str__(self):
        pass

class notatka(przedmiot):

    def __init__(self, priorytet, tytuł, treść):
        super().__init__("notatka", priorytet)
        self.tytuł = tytuł
        self.treść = treść

    def __str__(self):
        info = self.typ + "Priorytet " + self.priorytet + "\n"
        info += self.tytuł + "\n"
        info += self.treść + "\n"
        return  info

class wizytówka(przedmiot):
    
    def __init__(self, priorytet, imię, nazwisko, telefon):
        super().__init__("wizytówka", priorytet)
        self.imię = imię
        self.nazwisko = nazwisko
        self.telefon = telefon

    def __str__(self):
        info = self.typ + "Priorytet " + self.priorytet + "\n"
        info += self.imię + " " + self.nazwisko + "\n"
        info += self.telefon + "\n"
        return  info

a sam program, możemy uruchomić poleceniem

$ python3 run.py

Podsumowując. Po rozłożeniu na czynniki pierwsze, zadanie okazało się nie takie trudne. Dużej mieże jest to połączenie wszystkiego tego co do tej pory się nauczyliśmy. Oczywiście rozwiązanie jest jedynie przykładowym rozwiązaniem, a każdy z nas, mógł dojść samodzielnie do innego. Zanim przejdziemy dalej, zapraszamy do samodzielnego rozwiązania poniższych ćwiczeń.

Ćwiczenia. Tym razem, bez rozwiązania 🙂

Ćwiczenie 1. Należy dodać, do naszego programu, kolejny przedmiot. Mianowicie – kupon rabatowy

Ćwiczenie 2. Należy rozszerzyć funkcjonalność naszego organizera o możliwość skasowania wybranego przedmiotu.

Python, NIE tylko dla początkujących

  1. Wstęp do kursu
  2. Moduły i pakiety
  3. Programowanie obiektowe – wstęp
  4. Programowanie obiektowe – dziedziczenie
  5. Programowanie obiektowe – hermetyzacja
  6. Mini projekt – Organizer <– bieżąca lekcja
  7. Funkcje rekurencyjne w Python
  8. Pisanie skryptów w Python
  9. Mini projekt – tajny agent, generator haseł
  10. *args oraz **kwargs
  11. Dekoratory w Python
  12. Mini projekt – tajny agent – kontakty
  13. Odwzorowanie list
  14. Podsumowanie oraz dalsze kroki