Sortowanie

Kod nr 1

class Employee:

    def __init__(self, name, dept, salary):
        self.name = name
        self.dept = dept
        self.salary = salary

    def __repr__(self):
        return '{' + self.name + ', ' + self.dept + ', ' + str(self.salary) + '}'


workres = [
    Employee('James', 'Finance', 80000),
    Employee('Robert', 'Construction', 60000),
    Employee('James', 'Telecom', 70000)
]

# 1. Sort by only `dept` attribute
workres.sort(key=lambda x: x.dept)

# [{Robert, Construction, 60000}, {James, Finance, 80000}, {James, Telecom, 70000}]
print(workres)

# 2. Sort by `name` attribute, followed by `dept` attribute
workres.sort(key=lambda x: (x.name, x.dept))

# [{James, Finance, 80000}, {James, Telecom, 70000}, {Robert, Construction, 60000}]
print(workres)

# 3. Sort by `name` attribute in reverse order,
# , followed by `dept` attribute in reverse order
workres.sort(key=lambda x: (x.name, x.dept), reverse=True)

# [{Robert, Construction, 60000}, {James, Telecom, 70000}, {James, Finance, 80000}]
print(workres)

# 4. Sort by `name` attribute in the natural order,
# , followed by numeric `salary` attribute in reverse order
workres.sort(key=lambda x: (x.name, -x.salary))

# [{James, Finance, 80000}, {James, Telecom, 70000}, {Robert, Construction, 60000}]
print(workres)

Kod nr 2

from operator import attrgetter


class Employee:

    def __init__(self, name, dept):
        self.name = name
        self.dept = dept

    def __repr__(self):
        return '{' + self.name + ', ' + self.dept + '}'


workers = [
    Employee('James', 'Telecom'),
    Employee('Robert', 'Construction'),
    Employee('James', 'Finance')
]

# sort by `name` and `dept` attribute
workers.sort(key=attrgetter('name', 'dept'))

# [{James, Finance}, {James, Telecom}, {Robert, Construction}]
print(workers)

Kod nr 3

class Employee:

    def __init__(self, name, dept):
        self.name = name
        self.dept = dept

    def __repr__(self):
        return '{' + self.name + ', ' + self.dept + '}'


workers = [
    Employee('James', 'Telecom'),
    Employee('Robert', 'Construction'),
    Employee('James', 'Finance')
]

# sort by `name` and `dept` attribute
sortByNameAndDept = sorted(workers, key=lambda x: (x.name, x.dept))

# [{James, Finance}, {James, Telecom}, {Robert, Construction}]
print(sortByNameAndDept)

Kod nr 4

class Person(object):

    def __init__(self, firstname, lastname):
        self.first = firstname
        self.last = lastname

    def __eq__(self, other):
        return ((self.last, self.first) == (other.last, other.first))

    def __ne__(self, other):
        return ((self.last, self.first) != (other.last, other.first))

    def __lt__(self, other):
        return ((self.last, self.first) < (other.last, other.first))

    def __le__(self, other):
        return ((self.last, self.first) <= (other.last, other.first))

    def __gt__(self, other):
        return ((self.last, self.first) > (other.last, other.first))

    def __ge__(self, other):
        return ((self.last, self.first) >= (other.last, other.first))

    def __repr__(self):
        return "%s %s" % (self.first, self.last)
Operator Metoda
== __eq__
!= __ne__
< __lt__
<= __le__
> __gt__
>= __ge__

Ćwiczenia. Stwórz listę osób, książek, filmów itp i posortują ją różnymi sposobami.

Metody magiczne - więcej info

https://docs.python.org/3/reference/datamodel.html

__getitem__ daje dostęp do odczytu równoważny obj[i] i obj.__getitem__(i)

__setitem__ - dodaje możliwość zapisu zwartości, równoważnie s1.__setitem__(0,'hi') oraz s1[0]='hi'

Kod nr 5

class Building(object):
    def __init__(self, floors):
        self._floors = [None] * floors

    def occupy(self, floor_number, data):
        self._floors[floor_number] = data

    def get_floor_data(self, floor_number):
        return self._floors[floor_number]


building1 = Building(4)  # Construct a building with 4 floors
building1.occupy(0, 'Reception')
building1.occupy(1, 'ABC Corp')
building1.occupy(2, 'DEF Inc')
print(building1.get_floor_data(2))

Kod nr 6

class Building(object):
    def __init__(self, floors):
        self._floors = [None] * floors

    def __setitem__(self, floor_number, data):
        self._floors[floor_number] = data

    def __getitem__(self, floor_number):
        return self._floors[floor_number]


building1 = Building(4)  # Construct a building with 4 floors
building1[0] = 'Reception'
building1[1] = 'ABC Corp'
building1[2] = 'DEF Inc'
print(building1[2])

Kod nr 7

class Test:

    def __getitem__(self, items):
        print(type(items), items)


test = Test()
test[4]
test[5:65:5]
test['Olsztyn']

__init__ i __new__

https://pl.wikipedia.org/wiki/Konstruktor_(programowanie_obiektowe)

Kod nr 8

class Point:
    def __new__(cls, *args, **kwargs):
        print("1. Create a new instance of Point.")
        return super().__new__(cls)

    def __init__(self, x, y):
        print("2. Initialize the new instance of Point.")
        self.x = x
        self.y = y

    def __repr__(self) -> str:
        return f"{type(self).__name__}(x={self.x}, y={self.y})"


p = Point(4, 5)
print(p)

Kod nr 9

class Point:
    def __new__(cls, *args, **kwargs):
        print("1. Create a new instance of Point.")
        return super().__new__(cls)

    def __init__(self, x, y):
        print("2. Initialize the new instance of Point.")
        self.x = x
        self.y = y

    def __repr__(self) -> str:
        return f"{type(self).__name__}(x={self.x}, y={self.y})"


point = Point.__new__(Point)
# print(point.x)
point.__init__(21, 42)
print(point)

Kod nr 10

class A:
    def __init__(self, a_value):
        print("Initialize the new instance of A.")
        self.a_value = a_value


class B:
    def __new__(cls, *args, **kwargs):
        return A(42)

    def __init__(self, b_value):
        print("Initialize the new instance of B.")
        self.b_value = b_value


b = B(21)
# print(b.b_value)
print(isinstance(b, B))
print(isinstance(b, A))

Emulacja typów numerycznych

https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types

  • egzemplarz + innyobiekt uruchamia metodę __add__
  • egzemplarz + egzemplarz uruchamia metodę __add__
  • innyobiekt + egzemplarz uruchamia metodę __radd__

Kod nr 11

class X:
    def __init__(self, num):
        self.num = num


class Y:
    def __init__(self, num):
        self.num = num

    def __radd__(self, other_obj):
        return Y(self.num + other_obj.num)

    def __str__(self):
        return str(self.num)


x = X(2)
y = Y(3)
print(x + y)
print(y + x)

Kod nr 12

class Vector:
    def __init__(self, values):
        self.values = values

    def __add__(self, other):
        if isinstance(other, Vector):
            # Vector-vector addition
            return Vector([a + b for a, b in zip(self.values, other.values)])
        if type(other) in (int, float):
            # Vector-scalar addition
            return Vector([a + other for a in self.values])
        return NotImplemented


v1 = Vector([1, 2, 3])
v2 = v1 + 2  # Creates the vector [3, 4, 5]
v1 = Vector([1, 2, 3])
v2 = 2 + v1  # Raises an error

Kod nr 13

class Vector:
    def __init__(self, values):
        self.values = values

    def __add__(self, other):
        if isinstance(other, Vector):
            # Vector-vector addition
            return Vector([a + b for a, b in zip(self.values, other.values)])
        if type(other) in (int, float):
            # Vector-scalar addition
            return Vector([a + other for a in self.values])
        return NotImplemented

    def __radd__(self, other):
        if type(other) in (int, float):
            return Vector([a + other for a in self.values])
        return NotImplemented


v1 = Vector([1, 2, 3])
v2 = v1 + 2  # Creates the vector [3, 4, 5]
v1 = Vector([1, 2, 3])
v2 = 2 + v1  # Raises an error

Kopiowanie

old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 'a']]
new_list = old_list

new_list[2][2] = 9

print('Old List:', old_list)
print('ID of Old List:', id(old_list))

print('New List:', new_list)
print('ID of New List:', id(new_list))
import copy

old_list = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_list = copy.copy(old_list)

old_list.append([4, 4, 4])

print("Old list:", old_list)
print("New list:", new_list)
import copy

old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 'a']]
new_list = copy.copy(old_list)

new_list[2][2] = 9

print('Old List:', old_list)
print('ID of Old List:', id(old_list))

print('New List:', new_list)
print('ID of New List:', id(new_list))
import copy

old_list = [[1, 2, 3], [4, 5, 6], [7, 8, 'a']]
new_list = copy.deepcopy(old_list)

new_list[2][2] = 9

print('Old List:', old_list)
print('ID of Old List:', id(old_list))

print('New List:', new_list)
print('ID of New List:', id(new_list))

https://www.pythonforthelab.com/blog/deep-and-shallow-copies-of-objects/

Klasy abstrakcyjne

Służą przede wszystkim to zablokowania tworzenia instancji klasy, gdzie byt na górze drabiny dziedziczenia nie jest potrzebny. Metoda abstrakcyjna wymusza implementację metody w klasie pochodnej (o ile jest tworzona instancja obiektu).

Kod nr 1:

from abc import ABC, abstractmethod


class Polygon(ABC):
    @abstractmethod
    def noofsides(self):
        pass


class Triangle(Polygon):
    def noofsides(self):
        print("I have 3 sides")


class Pentagon(Polygon):
    def noofsides(self):
        print("I have 5 sides")


class Hexagon(Polygon):
    def noofsides(self):
        print("I have 6 sides")


class Quadrilateral(Polygon):
    def noofsides(self):
        print("I have 4 sides")


R = Triangle()
R.noofsides()
K = Quadrilateral()
K.noofsides()
R = Pentagon()
R.noofsides()
K = Hexagon()
K.noofsides()

Kod nr 2

from abc import ABC, abstractmethod


class Animal(ABC):
    def move(self):
        pass


class Human(Animal):
    def move(self):
        print("I can walk and run")


class Snake(Animal):
    def move(self):
        print("I can crawl")


class Dog(Animal):
    def move(self):
        print("I can bark")


class Lion(Animal):
    def move(self):
        print("I can roar")


R = Human()
R.move()
K = Snake()
K.move()
R = Dog()
R.move()
K = Lion()
K.move()

Kod nr 3

from abc import ABC


class BaseClass(ABC):
    def test(self):
        print("Abstract Base Class")


class ChildClass(BaseClass):
    def test(self):
        super().test()
        print("subclass ")


r = ChildClass()
r.test()