Języki skryptowe Python

Wykład 11

Programowanie strukturalne


  • sekwencje (ciąg instrukcji)
  • wybór (if)
  • iteracja (pętle for i while)
  • funkcje

Słownik


  • OOP - Object-Oriented Programming
  • klasa - definicja obiektu
  • instanacja (klasy) - obiekt utworzony na podstawie klasy

Klasy


  • Klasa

    • Atrybuty

      • Dane

      • Metody

Przykład - klasa complex


  • complex

    • Dane:

      • real

      • imag

    • Metody:

      • conjugate

Klasa complex


c = 10 + 5j    # utwórz obiekt klasy complex
c.real         # dane: real
10.0
c.imag         # dane: imag
5.0
c.conjugate()  # metody: conjugate
(10-5j)

Programowanie obiektowe


  • tworzenie obiektów
    • mogą przechowywać dane
    • mogą wykonywać opearacje
    • przykład: klasa samochód
      • dane: moc, masa, moment obrotowy ...
      • metody: jedź, skręć, ...
  • komunikacja między obiektami
    • przykład: klasa łyżka i klasa zupa
      • łyżka.pobierz(zupa)

Klasa w Pythonie


class Nazwa:
    instrukcje
    ...
  • zbudujemy krok po kroku klasę trójkąt:
    • dane: boki a, b, c
    • metody: pole, obwód, typ...

"Pusta" klasa


class Triangle:
    pass
# na razie klasa Triangle
# nie zawiera ani danych ani metod
# ale już możemy stworzyć obiekt typu Triangle

t = Triangle()
type(t)
__main__.Triangle

Uwaga


  • w Pythonie można dodawać atrybuty do istniejących obiektów (choć nie jest to zalecane!)
t.a = 3.0  # atrybut a obiektu t
t.b = 4.0  # atrybut b obiektu t
t.c = 5.0  # atrybut c obiektu t

print(t.a, t.b, t.c)  # drukuj atrybuty a, b, c
3.0 4.0 5.0
def drukuj(triangle):  # każdy obiekt może być argumentem funkcji
    print(triangle.a, triangle.b, triangle.c)
    
drukuj(t)
3.0 4.0 5.0

Inicjalizacja


  • __init__ - prawie jak konstruktor, ale wywoływana po utworzeniu instancji
  • self - odpowiednik this z c++
class Triangle:
    """Dokumentacja jak w przypadku funkcji"""
    
    def __init__(self, a, b, c):
        """Prawie jak konstruktor"""
        self.a = a  # zmiennej obiekt.a
        self.b = b  # przypisz wartość a
        self.c = c  # itd
t = Triangle(3, 4, 5)  # wywołuje funkcję __init__(3, 4, 5)
print(t.a, t.b, t.c)
3 4 5

self


  • pierwszy argument każdej metody = self
  • przyjęto konwencję self, ale może to być dowolna nazwa
class Triangle:
    """Dokumentacja jak w przypadku funkcji"""
    
    def __init__(this, a, b, c):
        """Prawie jak konstruktor"""
        this.a = a
        this.b = b
        this.c = c
# wywołuje funkcję __init__(3, 4, 5)
t = Triangle(3, 4, 5)
print(t.a, t.b, t.c)
3 4 5

Dokumentacja


help(t)
Help on Triangle in module __main__ object:

class Triangle(builtins.object)
    |  Dokumentacja jak w przypadku funkcji
    |  
    |  Methods defined here:
    |  
    |  __init__(this, a, b, c)
    |      Prawie jak konstruktor
    |  
    |  ----------------------------------------------------------------------
    |  Data descriptors defined here:
    |  
    |  __dict__
    |      dictionary for instance variables (if defined)
    |  
    |  __weakref__
    |      list of weak references to the object (if defined)

Metody specjalne


  • __init__ jest jedną z metod specjalnych klasy
  • tutaj znajduje się pełna lista dostępnych metod specjalnych
  • w trakcie wykładu pojawią się kolejne (wszystkie __nazwa__)

str i repr


  • __repr__ - "oficjalna" reprezentacja obiektu, powinna być jednoznaczna; wywołana przez repr(obiekt) lub w interpreterze po wpisaniu nazwy zmiennej
  • __str__ - "nieformalna" reprezentacja obiektu, powinna być czytelna; wywołana przez str(obiekt) lub print

Triangle : str i repr


class Triangle:
    # pomijamy dokumentację: oszczędność slajdu
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
        
    def __str__(self):  # zwraca string
        return "Trójkąt o bokach: {}, {}, {}"\
                .format(self.a, self.b, self.c)
    
    def __repr__(self):  # zwraca string
        return "Triangle({}, {}, {})"\
                .format(self.a, self.b, self.c)

Triangle : str i repr


t = Triangle(3, 4, 5)

print(t)  # wywołuje __str__
Trójkąt o bokach: 3, 4, 5
t  # (w interpreterze) wywołuje __repr__
Triangle(3, 4, 5)

Własne metody - obwód


class Triangle:

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
        
    def obwod(self):
        # do zmiennych obiektu odwołujemy się przez self.zmienna
        return self.a + self.b + self.c
t = Triangle(3, 4, 5)
t.obwod()
12

Własne metody - pole


from math import sqrt

class Triangle:

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
        
    def obwod(self):
        return self.a + self.b + self.c
    
    def pole(self):
        # do metod odwołujemy się przez self.metoda
        p = self.obwod()/2
        return sqrt(p*(p - self.a)*(p - self.b)*(p - self.c))

Test


t = Triangle(3, 4, 5)

print("Obwód =", t.obwod())
print("Pole =", t.pole())
Obwód = 12
Pole = 6.0

Klasa wektor


  • współrzędne x, y, z
  • długość wektora
  • dodawanie wektorów
  • mnożenie wektora przez liczbę
  • iloczyn skalarny
  • ...

Wektor: długość


from math import sqrt

class Wektor:
    """Trójwymiarowy wektor"""
    
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.x = x
        self.y = y
        self.z = z
        
    def norm(self):
        """Długość wektora"""
        return sqrt(self.x**2 + self.y**2 + self.z**2)

Długość: test


w = Wektor(1)  # utwórz wektor (1, 0, 0)

w.norm()
1.0
w.x = 2  # zmień składową x

w.norm()
2.0

Zmienne prywatne


class Wektor:
    """Trójwymiarowy wektor"""
    
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self._x = x  # zmienne "prywatne"
        self._y = y  # sygnalizuje się _
        self._z = z
        
    def __str__(self):
        return "[{}, {}, {}]".format(self._x, self._y, self._z)

Wektor prywatny


from wektor import Wektor

w = Wektor(1)  # utwórz wektor (1, 0, 0)

print(w)
[1, 0.0, 0.0]
# dostęp do _zmienna nie jest ograniczony
# jest to tylko wskazówka, żeby nie ruszać
w._x = 2.0

print(w)
[2.0, 0.0, 0.0]

Zmienne bardziej prywatne


class Wektor:
    """Trójwymiarowy wektor"""
    
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.__x = x  # zmienne zaczynające się __
        self.__y = y  # zamieniane są na
        self.__z = z  # _nazwa_klasy__zmienna
        
    def __str__(self):
        return "[{}, {}, {}]".format(self.__x, self.__y, self.__z)

Wektor bardziej prywatny


w = Wektor(1)  # [1, 0, 0]

print(w)
[1, 0.0, 0.0]
w.__x = 2  # nie zmienia skladowej __x

print(w)
[1, 0.0, 0.0]
w._Wektor__x = 2  # zmienia składową __x

print(w)
[2, 0.0, 0.0]

Dodawanie wektorów


class Wektor:
    """Trójwymiarowy wektor"""
    
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.x = x
        self.y = y
        self.z = z
        
    def __str__(self):
        return "[{}, {}, {}]".format(self.x, self.y, self.z)
        
    def __add__(self, w):  # operator dodawania
        return Wektor(self.x + w.x, self.y + w.y, self.z + w.z)

Dodawanie: test


x = Wektor(1, 2, 3)
y = Wektor(2, 4, 6)

print(x + y)  # wywołuje x.__add__(y)
[3, 6, 9]

Wektor: iloczyn skalarny


class Wektor:
    """Trójwymiarowy wektor"""
    
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.x = x
        self.y = y
        self.z = z
        
    def __str__(self):
        return "[{}, {}, {}]".format(self.x, self.y, self.z)
        
    def __mul__(self, w):  # operator mnożenia
        return self.x*w.x + self.y*w.y + self.z*w.z

Iloczyn skalarny: test


x = Wektor(1, 2, 3)
y = Wektor(2, 4, 6)

print(x*y)  # wywołuje x.__mul__(y)
28

Mnożenie przez liczbę


class Wektor:
    """Trójwymiarowy wektor"""
    
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.x = x
        self.y = y
        self.z = z
        
    def __str__(self):
        return "[{}, {}, {}]".format(self.x, self.y, self.z)
        
    def __mul__(self, w):          # operator mnożenia
        if type(w) == type(self):  # dla wektora - iloczyn skalarny
            return self.x*w.x + self.y*w.y + self.z*w.z
        else:                      # dla liczby - mnożenie składowych
            return Wektor(w*self.x, w*self.y, w*self.z)

Mnożenie: test


x = Wektor(1, 2, 3)
y = Wektor(2, 4, 6)

print(x*y)  # wywołuje x.__mul__(y)
28
print(x*10)  # mnoży wektor z przez 10
[10, 20, 30]
print(10*x)  # nie działa...
TypeError: unsupported operand type(s) for *: 'int' and 'Wektor'

Mnożenie z prawej


class Wektor:
    """Trójwymiarowy wektor"""
    
    def __init__(self, x=0.0, y=0.0, z=0.0):
        self.x = x
        self.y = y
        self.z = z
        
    def __str__(self):
        return "[{}, {}, {}]".format(self.x, self.y, self.z)
        
    def __mul__(self, w):          # operator mnożenia
        if type(w) == type(self):  # dla wektora - iloczyn skalarny
            return self.x*w.x + self.y*w.y + self.z*w.z
        else:                      # dla liczby - mnożenie składowych
            return Wektor(w*self.x, w*self.y, w*self.z)
        
    def __rmul__(self, w):  # mnożenie z prawej
        return self.__mul__(w)

Mnożenie z prawej: test


x = Wektor(1, 2, 3)

print(x*10)
[10, 20, 30]
print(10*x)
[10, 20, 30]