-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodule6_1.py
More file actions
185 lines (155 loc) · 9.32 KB
/
Copy pathmodule6_1.py
File metadata and controls
185 lines (155 loc) · 9.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# Запуск дополнительных тестов
# Если требуется проверка задания строго по ТЗ, установите значение в False
EXTRA_TESTS = False
class Living:
'''
Класс "Живое существо", имеющее название (имя), способное к обмену веществ с природой, и к смерти.
'''
alive = True
eats = set()
def __init__(self, name):
self.name = name
def __str__(self):
if self.alive:
return f'Живое существо "{self.name}"'
return f'Мертвое существо "{self.name}"'
def become_dead(self):
self.alive = False
class FoodTraits:
'''
Класс "Свойства пищи". При наследовании от него добавляет объекту свойства пищи (простите за тавтологию)
'''
# Изначально пища еще не съедена
edible = True
def is_edible(self):
return self.edible
def mark_eaten(self):
self.edible = False
def is_eaten(self):
return not self.edible
def food_status(self):
return f'Пища "{self.name}" {'еще не съедена' if self.edible else 'уже съедена'}'
# Класс "Растение" имеет те же свойства, что и класс "Живое существо".
Plant = Living
# Класс "Цветок" имеет те же свойства, что и класс "Растение".
Flower = Plant
class Fruit(Plant, FoodTraits):
'''
Класс "Фрукт", в контесте данной задачи, представляет собой сорванный съедобный плод какого либо "Растения".
По ТЗ все фрукты являются съедобными, что в реальности не так.
В данном решении фрукт (данный экземпляр класса Fruit) является съедобным до тех пор,
пока его кто-нибудь не съел. Логику предложенных в ТЗ тестов это не нарушает.
Наследование свойств пищи (от класса FoodTraits) устанавливает атрибут edible = True, т.е. только что созданный
объект имеет свойство еще не съеденной пищи.
'''
def __init__(self, name):
super().__init__(name)
# Хоть фрукт, как растение, в реальности является разновидностью живого существа,
# в контексте данной задачи представлется сорванным фруктом, т.е. уже не живым.
# Создавая объект, мы подразумеваем, что срываем фрукт, т.е. убиваем его. Аминь!
self.become_dead()
class Animal(Living, FoodTraits):
'''
Класс "Животное", в контексте данное задачи, является синонимом "Живого существа",
способного поглощать (eat) определенную пищу.
В ТЗ не сказано, что животное может быть съедено другим животным. Добавим еще частичку
реальности в наш "высокоабстрактный проект" - унаследуем свойства пищи (от класса FoodTraits).
Тем самым обозначим животное съедобным до момента, когда его уже кто-то съел.
'''
def __init__(self, name):
super().__init__(name)
# В общем случае, животное голодно.
self.fed = False
def can_eat(self, food):
'''
Определяет способность данного Животного поглощать указанный вид пищи
:param food: объект, характеризующий пищу
:return: True - если пища пригодна к употреблению, False - в противном случае
'''
# То, что умерло, есть не может
if not self.alive:
return False
for edible in self.eats:
if issubclass(type(food), edible):
# Если предлагаемый объект может служить пищей данного живого существа,
# у него должен быть метод is_eaten(), указывающий на то, съел ли уже кто-то эту пищу.
if not food.is_eaten():
return True
# Делаем вывод, что пища несъедобна
return False
def eat(self, food):
if self.can_eat(food):
# Если поглощаемая пища (food) до момента поглощения являлась живым существом,
# после поглощения становится неживым веществом природы.
if issubclass(type(food), Living):
food.become_dead()
# Еда может быть съедена только один раз
food.mark_eaten()
# Если пища успешно поглощено, считаем животное накормленным.
self.fed = True
# Торжественно сообщаем об успешном исходе трапезы
print(f'{self.name} съел {food.name}')
else:
# В ТЗ написано:
# ---
# Если переданное растение (food) не съедобное - выводит на экран
# "<self.name> не стал есть <food.name>", меняется атрибут alive на False.
# ---
# Однако становится не до конца понятной связь между "не стал есть" и "alive на False".
# - не съел, значит не отравился и тогда должен остаться живым
# - если умер от голода, то почему сразу?
self.become_dead()
# Выводим сообщение строго по ТЗ.
# Хотя, я бы фразу "не стал есть" заменил на "не переварил".
# Тогда стало бы понятно почему животное сразу умерло.
print(f'{self.name} не стал есть {food.name}')
class Mammal(Animal):
'''
Класс "Млекопитающее" представляет собой разновидность "Животного".
В контексте данной задачи способно поглощать "Фрукты".
'''
eats = { Fruit }
class Predator(Mammal):
'''
Класс "Хищник" представляет собой разновидность "Животного".
В контексте данной задачи способно поглощать "Фрукты" и других "Животных".
'''
eats = { Fruit, Animal }
# Начало тестов
a1 = Predator('Волк с Уолл-Стрит')
a2 = Mammal('Хатико')
p1 = Flower('Цветик семицветик')
p2 = Fruit('Заводной апельсин')
print(a1.name)
print(p1.name)
print(a1.alive)
print(a2.fed)
a1.eat(p1)
a2.eat(p2)
if EXTRA_TESTS:
# Попытка съесть одну и ту же пищу дважды будет неудачной
print(p2.food_status())
a2.eat(p2)
print(a1.alive)
print(a2.fed)
# Тесты в духе "сожрите друг друга"
if EXTRA_TESTS:
# Создаем абстрактоное млекопитающее и хищника
boris_the_pig = Mammal('Поросёнок Борька')
wolf_grey_and_terrible = Predator('Злой и страшный серый волк')
# Абстрактное млекопитающее не сможет съесть хищника и...
boris_the_pig.eat(wolf_grey_and_terrible)
# ...скончается от несбывшихся амбиций
print(boris_the_pig)
# Создаем новый экземпляр Mammal, т.к. предыдущий умер от голода, не съев хищника
boris_the_pig = Mammal('Поросёнок Борька (второе пришествие)')
# На данном этапе млекопитающее является не съеденной пищей хищника
print(boris_the_pig.food_status())
# Борис пока жив и здоров, но...
print(boris_the_pig)
# Хищник проглощает это наивное млекопитающее
wolf_grey_and_terrible.eat(boris_the_pig)
# На данном этапе млекопитающее является съеденной пищей хищника
print(boris_the_pig.food_status())
# Борис умер...
print(boris_the_pig)