Python · Синтаксис · Начальный уровень
ООП: наследование и dunder-методы
Задачи по ООП в Python на наследование и специальные методы: дочерние классы, переопределение поведения, __str__, __len__, расширение базовых классов и работа с объектной моделью.
Краткое введение в тему и пояснения перед упражнениями (упражнения ниже):
Dunder-методы — __str__ и __len__
#Паттерны наследования и dunder-методов
#Быстрый справочник: наследование и dunder-методы
#Упражнения:
Animal и Dog через наследование.
#class Animal:
pass
class Dog(Animal):
pass
Решение
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __str__(self):
return f"Dog: {self.name}"
# Можно детализировать:
class Dog(Animal):
def __str__(self):
return f"Dog: {self.name}"
def tell(self):
print("Bark!!!") # "Гав" по англ. Собакам тоже нужен переводчик..
class Cat(Animal):
def __str__(self):
return f"Cat: {self.name}"
def tell(self):
print("Cats don't care about human commands!")
# self все равно нужно принять даже если в методе не используется.
Book со строковым представлением.
#class Book:
pass
Решение
class Book:
def __init__(self, title, pages):
self.title = title
self.pages = pages
def __len__(self):
return self.pages
def __str__(self):
return f"Book: {self.title} ({self.pages} pages)"
User и Admin.
#class User:
pass
class Admin(User):
pass
Решение
class User:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class Admin(User):
def __str__(self):
return f"Admin: {self.name}"
Коробка с предметами.
#class Box:
pass
Решение
class Box:
def __init__(self, items_count):
self.items_count = items_count
def add(self, count=1):
self.items_count += count
def remove(self, count=1):
self.items_count -= count
def __len__(self):
return self.items_count
# Со списком посложнее и по другому:
class Box:
def __init__(self):
self.items = []
self.items_count = len(self.items)
def add(self, item):
self.items.append(item)
self.items_count = len(self.items)
def remove(self, item):
if item in self.items:
self.items.remove(item)
self.items_count = len(self.items)
else:
print("Кот из коробки говорит: Такого тут нет, досвидания!")
def __len__(self):
return self.items_count
Message со спам-флагом.
#class Message:
pass
Решение
class Message:
def __init__(self, text):
self.text = text
self.spam = None
self.spam_triggers = ["куплю", "дорого"] # Да я не говорил об этом,
# но и не запрещал.
def is_spam(self):
if self.spam is not None: # ниже пояснение, это я уже "загнул"
return self.spam
for trigger in self.spam_triggers:
if trigger in self.text:
self.spam = True
return True
self.spam = False
return False
def __len__(self):
return len(self.text)
# Наличие self.spam после первого вызова is_spam позволит при повторных проверках
# не запускать механизм проверки, а просто глянуть в УЖЕ РАССЧИТАНЫЙ атрибут (оптимизация).
m = Message("Куплю старые телевизоры дорого!!!")
if m.is_spam(): # ведется реальная проверка
...
if m.is_spam(): # уже возьмется из self.spam
...
Employee и Manager.
#class Employee:
pass
class Manager(Employee):
pass
Решение
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def change_salary(self, coef): # например коэффициент 1.1 - увеличить на 10%
self.salary = round(self.salary * coef) # без второго аргумента округлит до целого
class Manager(Employee):
def __str__(self):
return f"Manager {self.name} earns {self.salary}"
chel = Manager("Bob", 1000)
chel.change_salary(1.1)
print(chel) # Manager Bob earns 1100
Playlist и CustomPlaylist.
#class Playlist:
pass
Решение
class Playlist:
def __init__(self, songs): # 1 аргумент список с треками
self.songs = songs
def add(self, song):
if song not in self.songs:
self.songs.append(song)
def remove(self, song):
if song in self.songs:
self.songs.remove(song)
def reverse(self):
self.songs.reverse()
def __len__(self):
return len(self.songs)
def __bool__(self):
return bool(self.songs)
# или
# class Playlist:
# def __init__(self, *songs): # треки как отдельные аргументы
# self.songs = list(songs) # просто решил напомнить про *args
# # остальное такое же.
class CustomPlaylist(Playlist):
def add(self, song):
self.songs.append(song)
Именованный CustomPlaylist.
#class CustomPlaylist(Playlist):
def __init__???
???
def add(self, song):
self.songs.append(song)
Решение
class CustomPlaylist(Playlist):
def __init__(self, songs, name):
super().__init__(songs)
self.name = name
def add(self, song):
self.songs.append(song)
def __str__(self):
return f"Playlist: {self.name}"
MagicBox со случайным предметом.
#from random import choice # функция случайного выбора из последовательности
class Box:
def __init__(self):
self.items = []
self.items_count = len(self.items)
def add(self, item):
self.items.append(item)
self.items_count = len(self.items)
def remove(self, item):
if item in self.items:
self.items.remove(item)
self.items_count = len(self.items)
else:
print("Кот из коробки говорит: Такого тут нет, досвидания!")
def __len__(self):
return self.items_count
things = ["Шапка", "Зонтик", "Кружка"]
class MagicBox(Box):
def __init__(self):
...
Решение
from random import choice # функция случайного выбора из последовательности
class Box:
def __init__(self):
self.items = []
self.items_count = len(self.items)
def add(self, item):
self.items.append(item)
self.items_count = len(self.items)
def remove(self, item):
if item in self.items:
self.items.remove(item)
self.items_count = len(self.items)
else:
print("Кот из коробки говорит: Такого тут нет, досвидания!")
def __len__(self):
return self.items_count
things = ["Шапка", "Зонтик", "Кружка"]
class MagicBox(Box):
def __init__(self):
super().__init__()
self.items.append(choice(things))
self.items_count = len(self.items)
# ИЛИ:
class MagicBox(Box):
def __init__(self):
super().__init__()
self.add(choice(things)) # так круче
x = MagicBox()
print(x.items)