1. OOP Basic

1.1. Object Paradigm

  • Model world as objects that interacts with each other

class

Templates for objects.

objects

Instances of a class.

method

Function inside the class.

property
attribute
field

Variable inside the class. Also known as “Properties” or “Attributes”

1.2. Classes

  • Capitalized CamelCase name convention

  • Classes are templates for objects

Listing 1.22. Defining class. Classes should have capitalized name
class Iris:
    pass
Listing 1.23. Classes should have CamelCase names
class IrisSetosa:
    pass

1.2.1. Classes vs Instances

  • Instances are also known as Objects

  • Two newlines between class and code

  • snake_case names

../_images/blueprint.png

Figure 1.2. Intuition definition: Class is a blueprint, instances are homes made from this plan. Image source: [ImgFre19]

Listing 1.24. One class and one instance
class Iris:
    pass


flower = Iris()
Listing 1.25. One class and three instances
class Iris:
    pass


setosa = Iris()
versicolor = Iris()
virginica = Iris()
Listing 1.26. Three classes and three instances
class IrisSetosa:
    pass

class IrisVersicolor:
    pass

class IrisVirginica:
    pass


iris_setosa = IrisSetosa()
iris_versicolor = IrisVersicolor()
iris_virginica = IrisVirginica()

1.3. Fields

  • Fields are also known as “Properties” or “Attributes”

  • snake_case name convention

  • Fields are defined in __init__() method

  • Fields store information for instances

Listing 1.27. Classes can have multiple fields. All fields should be initialized in __init__() method.
class Iris:
    def __init__(self):
        self.sepal_length = 5.1
        self.sepal_width = 3.5
        self.petal_length = 1.4
        self.petal_width = 0.2
        self.species = 'setosa'


flower = Iris()

print(flower.sepal_length)  # 5.1
print(flower.sepal_width)   # 3.5
print(flower.species)       # 'setosa'

1.4. Initializer Method

  • __init__() is not a constructor!

  • It’s a first method run after object is initiated

  • All classes has default __init__()

  • Initialize all fields only in __init__

Listing 1.28. Class initialization
class Iris:
    def __init__(self, species):
        self.species = species


setosa = Iris(species='setosa')
print(setosa.species)
# setosa

virginica = Iris('virginica')
print(virginica.species)
# virginica

versicolor = Iris()
# TypeError: __init__() missing 1 required positional argument: 'species'
Listing 1.29. Method argument with default value
class Iris:
    def __init__(self, species=None):
        self.species = species


setosa = Iris(species='setosa')
print(setosa.species)
# setosa

virginica = Iris('virginica')
print(virginica.species)
# virginica

versicolor = Iris()
# None

1.5. Methods

  • Methods are functions in the class

  • First argument is always instance (self)

  • While calling function you never pass self

1.5.1. Simple Methods

Listing 1.30. Simple Methods
class Iris:
    def __init__(self):
        self.species = 'setosa'

    def latin_name(self):
        print(f'Latin name is: Iris setosa')


flower = Iris()
flower.latin_name()
# Latin name is: Iris setosa

1.5.2. Methods accessing fields

Listing 1.31. Methods accessing fields
class Iris:
    def __init__(self):
        self.species = 'setosa'

    def latin_name(self):
        print(f'Latin name is: Iris {self.species}')


flower = Iris()
flower.latin_name()
# Latin name is: Iris setosa

1.5.3. Methods with argument

Listing 1.32. Methods with arguments
class Iris:
    def latin_name(self, species):
        print(f'Iris {species}')


flower = Iris()

flower.latin_name(species='setosa')  # Iris setosa
flower.latin_name('setosa')          # Iris setosa
flower.latin_name()                  # TypeError: latin_name() missing 1 required positional argument: 'species'

1.5.4. Methods with arguments with default value

Listing 1.33. Methods with default arguments
class Iris:
    def latin_name(self, species='unknown'):
        print(f'Iris {species}')


flower = Iris()

flower.latin_name(species='setosa')  # Iris setosa
flower.latin_name('setosa')          # Iris setosa
flower.latin_name()                  # Iris unknown

1.5.5. Methods calling other methods

Listing 1.34. Methods call other methods
class Iris:
    def __init__(self):
        self.sepal_length = 5.1
        self.sepal_width = 3.5
        self.petal_length = 1.4
        self.petal_width = 0.2
        self.species = 'setosa'

    def sepal_area(self):
        return self.sepal_length * self.sepal_width

    def petal_area(self):
        return self.petal_length * self.petal_width

    def total_area(self):
        area = self.sepal_area() + self.petal_area()
        print(f'Total area is: {area:.1f}')


flower = Iris()
flower.total_area()
# Total area is: 18.1

1.6. One class per file?

  • Osobne pliki - gdy klasy są duże

  • Jeden plik - gdy klasy są małe i czytelne

Listing 1.35. Classes and Objects
class IrisSetosa:
    pass

class IrisVersicolor:
    pass

class IrisVirginica:
    pass


setosa = IrisSetosa()
versicolor = IrisVersicolor()
virginica = IrisVirginica()

1.7. Assignments

1.7.1. Defining Classes

  • Filename: oop_iris.py

  • Lines of code to write: 15 lines

  • Estimated time of completion: 10 min

  1. Stwórz klasę Iris z polami:

    • sepal_length: float,

    • sepal_width: float,

    • petal_length: float,

    • petal_width: float,

    • species: str.

  2. Napisz metodę total() wyliczającą sumę dla pól numerycznych obiektu (sepal_length, sepal_width, petal_length, petal_width)

  3. Napisz metodę average() wyliczającą średnią dla powyższych pól

  4. Stwórz obiekt setosa z pomiarami:

    • sepal_length: 5.4

    • sepal_width: 3.9

    • petal_length: 1.3

    • petal_width: 0.4

  5. Wyświetl na ekranie nazwę gatunku oraz sumę i średnią z pomiarów.

1.7.2. Dragon (Part 1)

  • Filename: oop_dragon_1.py

  • Lines of code to write: 100 lines

  • Estimated time of completion: 75 min

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

../_images/dragon.gif

Figure 1.3. Firkraag dragon from game Baldur’s Gate II: Shadows of Amn

  1. Nie musisz trzymać się kolejności punktów i podpunktów w zadaniu

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

  3. Smok ma mieć:

    • nazwę

    • pozycję x na ekranie

    • pozycję y na ekranie

    • nazwę pliku tekstury, domyślnie img/dragon/alive.png

    • punkty życia, domyślnie losowy int z zakresu od 50 do 100

  4. Smok może:

    • być ustawiony w dowolne miejsce ekranu

    • zadawać komuś losowe obrażenia z przedziału od 5 do 20

    • otrzymywać obrażenia

    • być przesuwany o zadaną liczbę punktów w którymś z kierunków

  5. Przyjmij górny lewy róg ekranu za punkt (x=0, y=0)

    • idąc w prawo dodajesz x

    • idąc w lewo odejmujesz x

    • idąc w górę odejmujesz y

    • idąc w dół dodajesz y

  6. Przy każdym obrażeniu wypisz na ekranie nazwę smoka, ilość obrażeń i pozostałe punkty życia

  7. Nie można zadawać smokowi obrażeń, jeżeli już nie żyje

  8. Kiedy punkty życia smoka spadną do, lub poniżej zera:

    • ustaw status obiektu na dead

    • na ekranie ma pojawić się napis XXX is dead gdzie XXX to nazwa smoka

    • zmień nazwę pliku tekstury na img/dragon/dead.png

    • na ekranie pojawi się informacja ile złota smok wyrzucił (losowa 1-100)

    • na ekranie pojawi się informacja o pozycji gdzie smok zginął

  9. Przeprowadź grę:

    • Stwórz smoka w pozycji x=50, y=120 i nazwij go Wawelski

    • Ustaw nową pozycję na x=10, y=20

    • Przesuń smoka o 10 w lewo i 20 w dół

    • Przesuń smoka o 10 w lewo i 15 w prawo

    • Przesuń smoka o 15 w prawo i 5 w górę

    • Przesuń smoka o 5 w dół

    • Zadaj 10 obrażeń smokowi

    • Zadaj 5 obrażeń smokowi

    • Zadaj 3 obrażeń smokowi

    • Zadaj 2 obrażeń smokowi

    • Zadaj 15 obrażeń smokowi

    • Zadaj 25 obrażeń smokowi

    • Zadaj 75 obrażeń smokowi