[ Сборник задач ]
Тема 13. Классы и объекты

[ Сборник задач ]
Тема 13. Классы и объекты

Python Workbook Cover T1
  • Операторы: class
  • Контент: Вопросы (5шт) + задачи (5шт)

Оглавление

1
Введение
Рассмотрим специфику ООП в Python, структуру класса и вызов его экземпляров. Определим особенности методов и свойств классов. Ознакомимся с основными магическими методами (__str__, __repr__, __gt__, __slots__ и др.). Научимся модифицировать атрибуты в плане приватности доступа к ним.
Перейти
2
Вопросы и ответы
5 вопросов по теме "Классы и объекты" + ответы
Перейти
3
Условия задач
5 задач по теме двух уровней сложности: Базовый и *Продвинутый
Перейти
4
Решения задач
Приводим код решений указанных выше задач
Перейти
1
One

Введение

Объектно-ориентированное программирование (ООП) – один из подходов к реализации программного кода для проецирования сущностей реального мира. Считается, что введение классов и объектов упрощает понимание кода человеком. В Питоне все является объектами.

Для решения заданий потребуется усвоение следующих тем:
  1. Принципы ООП и их реализация в Python;
  2. Свойства и методы классов;
  3. Инициализация экземпляров классов;
  4. Получение и задание свойств через декораторы;
  5. Классовые и статические методы;
  6. Магические (dunder или magic) методы классов;
  7. Модификаторы доступа к методам и свойствам;
  8. Дескрипторы.

Читайте также

2
Two

Вопросы по теме "Классы и объекты"

3
Three

Задание по теме "Классы и объекты"

Задача 1
Создайте класс Soda (для определения типа газированной воды), принимающий 1 аргумент при инициализации (отвечающий за добавку к выбираемому лимонаду). В этом классе реализуйте метод show_my_drink(), выводящий на печать Газировка и {ДОБАВКА} в случае наличия добавки, а иначе отобразится следующая фраза: Обычная газировка.
Задача 2
Николаю требуется проверить, возможно ли из представленных отрезков условной длины сформировать треугольник. Для этого он решил создать класс TriangleChecker, принимающий только положительные числа. С помощью метода is_triangle() возвращаются следующие значения (в зависимости от ситуации):
Ура, можно построить треугольник!;
С отрицательными числами ничего не выйдет!;
Нужно вводить только числа!;
Жаль, но из этого треугольник не сделать.
Задача 3
Евгения создала класс KgToPounds с параметром kg, куда передается определенное количество килограмм, а с помощью метода to_pounds() они переводятся в фунты. Чтобы закрыть доступ к переменной kg она реализовала методы set_kg() - для задания нового значения килограммов, get_kg() - для вывода текущего значения кг. Из-за этого возникло неудобство: нам нужно теперь использовать эти 2 метода для задания и вывода значений. Помогите ей переделать класс с использованием функции property() и свойств-декораторов. Код приведен ниже.

Пример – IDE
---
class KgToPounds:

____def __init__(self, kg):
________self.__kg = kg

____def to_pounds(self):
________return self.__kg * 2.205

____def set_kg(self, new_kg):
________if isinstance(new_kg, (int, float)):
____________self.__kg = new_kg
________else:
____________raise ValueError('Килограммы задаются только числами')

____def get_kg(self):
________return self.__kg

Задача 4
Николай – оригинальный человек. Он решил создать класс Nikola, принимающий при инициализации 2 параметра: имя и возраст. Но на этом он не успокоился. Не важно, какое имя передаст пользователь при создании экземпляра, оно всегда будет содержать Николая. В частности - если пользователя на самом деле зовут Николаем, то с именем ничего не произойдет, а если его зовут, например, Максим, то оно преобразуется в Я не Максим, а Николай.

Более того, никаких других атрибутов и методов у экземпляра не может быть добавлено, даже если кто-то и вздумает так поступить (т.е. если некий пользователь решит прибавить к экземпляру свойство отчество или метод приветствие, то ничего у такого хитреца не получится).
Задача 5*
Строки в Питоне сравниваются на основании значений символов. Т.е. если мы захотим выяснить, что больше: Apple или Яблоко, – то Яблоко окажется бОльшим. А все потому, что английская буква A имеет значение 65 (берется из таблицы кодировки), а русская буква Я 1071 (с помощью функции ord() это можно выяснить). Такое положение дел не устроило Анну. Она считает, что строки нужно сравнивать по количеству входящих в них символов.

Для этого девушка создала класс RealString и реализовала озвученный инструментарий. Сравнивать между собой можно как объекты класса, так и обычные строки с экземплярами класса RealString. К слову, Анне понадобилось только 3 метода внутри класса (включая __init__()) для воплощения задуманного.
4
Two

Решение

Задача 1. Базовый уровень

Условие

Создайте класс Soda (для определения типа газированной воды), принимающий 1 аргумент при инициализации (отвечающий за добавку к выбираемому лимонаду). 
В этом классе реализуйте метод show_my_drink(), выводящий на печать «Газировка и {ДОБАВКА}» в случае наличия добавки, а иначе отобразится следующая фраза: «Обычная газировка».
При решении задания можно дополнительно проверить тип передаваемого аргумента: принимается только строка.
Решение - IDE

class Soda:
    def __init__(self, ingredient=None):
        if isinstance(ingredient, str):
            self.ingredient = ingredient
        else:
            self.ingredient = None

    def show_my_drink(self):
        if self.ingredient:
            print(f'Газировка и {self.ingredient}')
        else:
            print('Обычная газировка')

 
# Тесты
drink1 = Soda()
drink2 = Soda('малина')
drink3 = Soda(5)
drink1.show_my_drink()
drink2.show_my_drink()
drink3.show_my_drink()
Результат выполнения

Обычная газировка
Газировка и малина
Обычная газировка

Задача 2. Базовый уровень

Условие

Николаю требуется проверить, возможно ли из представленных отрезков условной длины сформировать треугольник. 
Для этого он решил создать класс TriangleChecker, принимающий только положительные числа. 
С помощью метода is_triangle() возвращаются следующие значения (в зависимости от ситуации):
– Ура, можно построить треугольник!;
– С отрицательными числами ничего не выйдет!;
– Нужно вводить только числа!;
– Жаль, но из этого треугольник не сделать.
Построить треугольник из отрезков можно лишь в одном случае: сумма длин двух любых сторон всегда больше третьей.
Решение - IDE

class TriangleChecker:
    def __init__(self, sides):
        self.sides = sides

    def is_triangle(self):
        if all(isinstance(side, (int, float)) for side in self.sides):
            if all(side > 0 for side in self.sides):
                sorted_sides = sorted(self.sides)
                if sorted_sides[0] + sorted_sides[1] > sorted_sides[2]:
                    return 'Ура, можно построить треугольник!'
                return 'Жаль, но из этого треугольник не сделать'
            return 'С отрицательными числами ничего не выйдет!'
        return 'Нужно вводить только числа!'
 
 
# Тесты
triangle1 = TriangleChecker([2, 3, 4])
print(triangle1.is_triangle())
triangle2 = TriangleChecker([77, 3, 4])
print(triangle2.is_triangle())
triangle3 = TriangleChecker([77, 3, 'Сторона3'])
print(triangle3.is_triangle())
triangle4 = TriangleChecker([77, -3, 4])
print(triangle4.is_triangle())
Результат выполнения

Ура, можно построить треугольник!
Жаль, но из этого треугольник не сделать
Нужно вводить только числа!
С отрицательными числами ничего не выйдет!

Задача 3. Базовый уровень

Условие

Евгения создала класс KgToPounds с параметром kg, куда передается определенное количество килограмм, а с помощью метода to_pounds() они переводятся в фунты. Чтобы закрыть доступ к переменной “kg” она реализовала методы set_kg() - для задания нового значения килограммов, get_kg()  - для вывода текущего значения кг. Из-за этого возникло неудобство: нам нужно теперь использовать эти 2 метода для задания и вывода значений. Помогите ей переделать класс с использованием функции property() и свойств-декораторов. Код приведен ниже.
 

class KgToPounds:

    def __init__(self, kg):
        self.__kg = kg

    def to_pounds(self):
        return self.__kg * 2.205

    def set_kg(self, new_kg):
        if isinstance(new_kg, (int, float)):
            self.__kg = new_kg
        else:
            raise ValueError('Килограммы задаются только числами')
    
    def get_kg(self):
        return self.__kg

Чтобы не задавать новые значения или не получать к ним доступ через два метода, можно реализовать предложенный класс через функцию property() или свойства-декораторы.
Вариант решения 1. Функция property()
Решение - IDE

class KgToPounds:
    def __init__(self, kg):
        self.__kg = kg

    def to_pounds(self):
        return self.__kg * 2.205

    def __set_kg(self, new_kg):
        if isinstance(new_kg, (int, float)):
            self.__kg = new_kg
        else:
            raise ValueError('Килограммы задаются только числами')

    def __get_kg(self):
        return self.__kg

    kg = property(__get_kg, __set_kg)
Вариант решения 2. Свойства-декораторы
Решение - IDE

class KgToPounds:
    def __init__(self, kg):
        self.__kg = kg

    def to_pounds(self):
        return self.__kg * 2.205
   
    @property
    def kg(self):
        return self.__kg
    
    @kg.setter
    def kg(self, new_kg):
        if isinstance(new_kg, (int, float)):
            self.__kg = new_kg
        else:
            raise ValueError('Килограммы задаются только числами')
 
 
# Тесты
weight = KgToPounds(12)
print(weight.to_pounds())
print(weight.kg)
weight.kg = 41
print(weight.kg)
weight.kg = 'десять'
Результат выполнения

26.46
12
41
ValueError: Килограммы задаются только числами

Задача 4. Базовый уровень

Условие

Николай – оригинальный человек. 
Он решил создать класс Nikola, принимающий при инициализации 2 параметра: имя и возраст. Но на этом он не успокоился. 
Не важно, какое имя передаст пользователь при создании экземпляра, оно всегда будет содержать “Николая”. 
В частности - если пользователя на самом деле зовут Николаем, то с именем ничего не произойдет, а если его зовут, например, Максим, то оно преобразуется в “Я не Максим, а Николай”.
Более того, никаких других атрибутов и методов у экземпляра не может быть добавлено, даже если кто-то и вздумает так поступить (т.е. если некий пользователь решит прибавить к экземпляру свойство «отчество» или метод «приветствие», то ничего у такого хитреца не получится).
Для ограничения количества наборов свойств и методов в экземпляре применяется специальный магический атрибут __slots__.
Решение - IDE

class Nikola:
	__slots__ = ['name', 'age']
 
	def __init__(self, name, age):
    	if name == 'Николай':
            self.name = name
        else:
            self.name = f'Я не {name}, а Николай'
    	self.age = age
 
 
# Тесты
person1 = Nikola('Иван', 31)
person2 = Nikola('Николай', 14)
print(person1.name)
print(person2.name)
person2.surname = 'Петров'
Результат выполнения

Я не Иван, а Николай
Николай
AttributeError: 'Nikola' object has no attribute 'surname'

Задача 5*. Продвинутый уровень

Условие

Строки в Питоне сравниваются на основании значений символов. 
Т.е. если мы захотим выяснить, что больше: «Apple» или «Яблоко», – то «Яблоко» окажется бОльшим. 
А все потому, что английская буква «A» имеет значение 65 (берется из таблицы кодировки), а русская буква «Я» – 1071 (с помощью функции ord() это можно выяснить). 
Такое положение дел не устроило Анну. 
Она считает, что строки нужно сравнивать по количеству входящих в них символов.
Для этого девушка создала класс RealString и реализовала озвученный инструментарий. Сравнивать между собой можно как объекты класса, так и обычные строки с экземплярами класса RealString. 
К слову, Анне понадобилось только 3 метода внутри класса (включая __init__()) для воплощения задуманного.
В общем случае для создания такого класса понадобится 4 метода, так как в Питоне реализованы «богатые» сравнения. Это значит, что если имеется сравнение «больше», то автоматом появится возможность осуществлять сравнение «меньше».
Решение - IDE

class RealString:
	def __init__(self, some_str):
    	self.some_str = str(some_str)
 
	def __eq__(self, other):
    	if not isinstance(other, RealString):
        	other = RealString(other)
    	return len(self.some_str) == len(other.some_str)
 
	def __lt__(self, other):
    	if not isinstance(other, RealString):
        	other = RealString(other)
    	return len(self.some_str) < len(other.some_str)
 
	def __le__(self, other):
    	return self == other or self < other
Чтобы повторить класс, придуманный Анной (с тремя методами), требуется воспользоваться декоратором @total_ordering из модуля functools (упрощает реализацию сравнений. Требует лишь 2 дополняющих варианта сравнения - например, больше и равно - чтобы автоматически "дописать" остальные).
Решение - IDE

from functools import total_ordering
 
 
@total_ordering
class RealString:
	def __init__(self, some_str):
    	self.some_str = str(some_str)
 
	def __eq__(self, other):
    	if not isinstance(other, RealString):
        	other = RealString(other)
    	return len(self.some_str) == len(other.some_str)
 
	def __lt__(self, other):
    	if not isinstance(other, RealString):
        	other = RealString(other)
    	return len(self.some_str) < len(other.some_str)
 
 
# Тесты
str1 = RealString('Молоко')
str2 = RealString('Абрикосы растут')
str3 = 'Золото'
str4 = [1, 2, 3]
print(str1 < str4)
print(str1 >= str2)
print(str1 == str3)
Результат выполнения

True
False
True
Как вам материал?

Читайте также