7. OOP Intermediate

7.1. Initial arguments mutability and shared state

7.1.1. Bad

Listing 281. Initial arguments mutability and shared state
class Contact:
    def __init__(self, name, addresses=[]):
        self.name = name
        self.addresses = addresses


jose = Contact(name='Jose Jimenez')

jose.addresses.append('2101 E NASA Pkwy, Houston, TX')
print('Jose:', jose.addresses)
# [2101 E NASA Pkwy, Houston, TX]

ivan = Contact(name='Ivan Ivanovich')
print('Ivan:', ivan.addresses)
# [2101 E NASA Pkwy, Houston, TX]

7.1.2. Good

Listing 282. Initial arguments mutability and shared state
class Contact:
    def __init__(self, name, addresses=()):
        self.name = name
        self.addresses = list(addresses)


jose = Contact(name='Jose Jimenez')
jose.addresses.append('2101 E NASA Pkwy, Houston, TX')
print(jose.addresses)
# [2101 E NASA Pkwy, Houston, TX]

ivan = Contact(name='Ivan Ivanovich')
print(ivan.addresses)
# []

7.2. Relations

class Address:
    def __init__(self, street=None, city=None, country=None):
        self.street = street
        self.city = city
        self.country = country


class Contact:
    def __init__(self, first_name, last_name, addresses=()):
        self.first_name = first_name
        self.last_name = last_name
        self.address = addresses


twardowski = Contact(first_name='Jan', last_name='Twardowski', address=[
    Address(street='Kamienica Pod św. Janem Kapistranem', city='Kraków', country='Poland'),
    Address(street='2101 E NASA Pkwy', city='Houston', country='USA'),
    Address(city='Kennedy Space Center', country='USA'),
])

7.3. Assignments

7.3.1. Defining Classes

Listing 283. Iris sample dataset
DATA = [
    ('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
    (5.8, 2.7, 5.1, 1.9, 'virginica'),
    (5.1, 3.5, 1.4, 0.2, 'setosa'),
    (5.7, 2.8, 4.1, 1.3, 'versicolor'),
    (6.3, 2.9, 5.6, 1.8, 'virginica'),
    (6.4, 3.2, 4.5, 1.5, 'versicolor'),
    (4.7, 3.2, 1.3, 0.2, 'setosa'),
    (7.0, 3.2, 4.7, 1.4, 'versicolor'),
    (7.6, 3.0, 6.6, 2.1, 'virginica'),
    (4.9, 3.0, 1.4, 0.2, 'setosa'),
    (4.9, 2.5, 4.5, 1.7, 'virginica'),
    (7.1, 3.0, 5.9, 2.1, 'virginica'),
    (4.6, 3.4, 1.4, 0.3, 'setosa'),
    (5.4, 3.9, 1.7, 0.4, 'setosa'),
    (5.7, 2.8, 4.5, 1.3, 'versicolor'),
    (5.0, 3.6, 1.4, 0.3, 'setosa'),
    (5.5, 2.3, 4.0, 1.3, 'versicolor'),
    (6.5, 3.0, 5.8, 2.2, 'virginica'),
    (6.5, 2.8, 4.6, 1.5, 'versicolor'),
    (6.3, 3.3, 6.0, 2.5, 'virginica'),
    (6.9, 3.1, 4.9, 1.5, 'versicolor'),
    (4.6, 3.1, 1.5, 0.2, 'setosa'),
]
  1. Stwórz flowers: list

  2. Stwórz klasy Virginica, Versicolor, Setosa, które będą identyczne do Iris

  3. Iterując po DATA z Listing 283.:

    1. Twórz obiekty klasy odpowiedniej dla nazwy gatunku (ostatni rekord każdej z krotek)

    2. Obiekt inicjalizuj danymi z pomiarów

    3. Obiekt dodaj do listy flowers

  4. Na ekranie wyświetlaj nazwę gatunku oraz sumę i średnią z pomiarów.

Dla chętnych
  1. Wynik sformatuj aby wyglądał jak tabelka:

    Species    Total   Avg
    ----------------------
     virginica  15.5  3.88
        setosa  10.2  2.55
    versicolor  13.9  3.48
     virginica  16.6  4.15
    versicolor  15.6  3.90
        setosa   9.4  2.35
    versicolor  16.3  4.07
     virginica  19.3  4.83
        setosa   9.5  2.38
        setosa   9.4  2.35
    

7.3.2. Basic Address Book

  1. Dla danych z listingu poniżej napisz książkę adresową

    Listing 284. Address Book
    [
        {"first_name": "Jan", "last_name": "Twardowski", "addresses": [
            {"street": "Kamienica Pod św. Janem Kapistranem", "city": "Kraków", "post_code": "31-008", "region": "Malopołskie", "country": "Poland"}]},
    
        {"first_name": "José", "last_name": "Jiménez", "addresses": [
            {"street": "2101 E NASA Pkwy", "city": "Houston", "post_code": 77058, "region": "Texas", "country": "USA"},
            {"street": "", "city": "Kennedy Space Center", "post_code": 32899, "region": "Florida", "country": "USA"}]},
    
        {"first_name": "Mark", "last_name": "Watney", "addresses": [
            {"street": "4800 Oak Grove Dr", "city": "Pasadena", "post_code": 91109, "region": "California", "country": "USA"},
            {"street": "2825 E Ave P", "city": "Palmdale", "post_code": "93550", "region": "California", "country": "USA"}]},
    
        {"first_name": "Иван", "last_name": "Иванович", "addresses": [
            {"street": "", "city": "Космодро́м Байкону́р", "post_code": "", "region": "Кызылординская область", "country": "Қазақстан"},
            {"street": "", "city": "Звёздный городо́к", "post_code": 141160, "region": "Московская область", "country": "Россия"}]},
    
        {"first_name": "Melissa", "last_name": "Lewis", "addresses": []},
    
        {"first_name": "Alex", "last_name": "Vogel", "addresses": [
            {"street": "Linder Hoehe", "city": "Köln", "post_code": 51147, "region": "North Rhine-Westphalia", "country": "Germany"}]}
    ]
    
  2. W zadaniu mamy do czynienia z trzema klasami, wymień je.

  3. Zamodeluj problem wykorzystując trzy klasy i relacje między nimi

  4. Użytkownik może mieć wiele adresów

  5. Użytkownik może nie mieć żadnego adresu

The whys and wherefores
  • myślenie obiektowe i odwzorowanie struktury w programie

  • praca z obiektami

  • zagnieżdżanie obiektów

  • rzutowanie obiektu na str oraz jego reprezentacja (które i kiedy użyć)

7.3.3. Address Book from API

  1. API programu powinno być tak jak na Listing 285.

  2. Zrób tak, aby się ładnie wyświetlało zarówno dla jednego wyniku jak i dla wszystkich w książce

  3. Address ma mieć zmienną liczbę argumentów

The whys and wherefores
  • Korzystanie z .__str__()

Listing 285. Address Book
class AddressBook:
    pass

class Contact:
    pass

class Address:
    pass


melissa = Contact(imie='Melissa', nazwisko='Lewis')
print(melissa)
# Melissa Lewis

mark = Contact(imie='Mark', nazwisko='Watney', adresy=[Address(miasto='Houston'), Address(miasto='Cocoa Beach')])
print(mark)
# Mark Watney [Houston, Cocoa Beach]

addressbook = AddressBook([
    Contact(imie='Jan', nazwisko='Twardowski', adresy=[
        Address(ulica='2101 E NASA Pkwy', miasto='Houston', stan='Texas', kod='77058', panstwo='USA'),
        Address(ulica=None, miasto='Kennedy Space Center', kod='32899', panstwo='USA'),
        Address(ulica='4800 Oak Grove Dr', miasto='Pasadena', kod='91109', panstwo='USA'),
        Address(ulica='2825 E Ave P', miasto='Palmdale', stan='California', kod='93550', panstwo='USA'),
    ]),
    Contact(imie='José', nazwisko='Jiménez'),
    Contact(imie='Иван', nazwisko='Иванович', adresy=[]),
])


print(addressbook)
# [Jan Twardowski [Houston, Kennedy Space Center, Pasadena, Palmdale], José Jiménez, Иван Иванович]

7.3.4. Dragon (version beta)

  • Filename: solution/intermediate_dragon.py

  • Lines of code to write: 120 lines

  • Estimated time of completion: 30 min (±10 min), then 30 min live coding with instructor

  • Warning: Don't delete code, assignment will be continued

../_images/dragon.gif

Figure 35. Firkraag dragon from game Baldur's Gate II: Shadows of Amn

  1. Zaimportuj smoka z poprzedniej części zadania ("Part 1")

  2. Wykorzystaj mechanizm dziedziczenia dla Smoka

  3. Nie modyfikuj klasy smoka z poprzedniej części

  4. Smok nie może wyjść poza obszar ekranu (1024x768) + napisz doctest

  5. Jeżeli dojdzie do granicy ekranu, to przesuwając dalej, pozycja będzie ustawiona na maks

  6. Zmień smokowi punkty życia na losowy int z zakresu 100 do 150

  7. Stwórz bohatera "Jan Twardowski":

    • losowe punkty życia (200-250)

    • zadaje losowe obrażenia (1-15)

    • klasa postaci (domyślnie "Warrior")

    • Bohater może przyjmować obrażenia

    • Bohater może zginąć

    • Bohater może poruszać się po planszy

  8. Wszystkie istoty mają statusy:

    • "Full Health" - gdy punkty życia 100% (zastąp status "alive")

    • "Injured" - gdy punkty życia 99% - 75%

    • "Badly Wounded" - gdy punkty życia 74% - 25%

    • "Near Death" - gdy punkty życia 24% - 1%

    • "Dead" - gdy punkty życia poniżej lub równe 0%

  9. Bohater przejmuje złoto smoka, jeżeli go zabije

  10. Przeprowadź walkę, tak długo aż ktoś pierwszy nie zginie

  11. Jeżeli konieczne jest wprowadzenie nowej metody, klasy lub pól to należy to zrobić

Hint
  • Aby zaimportować trzeba najpierw w katalogu stworzyć pusty plik __init__.py