-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodule5_2.py
More file actions
281 lines (228 loc) · 12.3 KB
/
Copy pathmodule5_2.py
File metadata and controls
281 lines (228 loc) · 12.3 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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# Ваша задача:
# 1. Создайте новый класс House
# 2. Создайте инициализатор для класса House, который будет задавать атрибут этажности self.numberOfFloors = 0
# 3. Создайте метод setNewNumberOfFloors(floors), который будет изменять атрибут numberOfFloors на параметр floors и выводить в консоль numberOfFloors
# 4. Полученный код напишите в ответ к домашнему заданию
# Скромное задание, подумал я...
# И решил поупражняться с классами как следует.
# Объектная модель спроектирована без должной глубины мысли, но критика все-равно приветствуется.
# Не полагаемся на внешние модули, а используем управляющие последовательности терминала ANSI
# Стиль текста оглавлений
def heading(text):
print(f'\033[1m\033[30m\033[42m{text}\033[0m')
# Стиль текста повествования
def narrative(text):
print(f'\033[3m\033[32m{text}\033[0m')
class Building:
'''
Абстрактное многоэтажное строение, характеризуемое только числом этажей
'''
# Число этажей является частным атрибутом, и доступен только через вызов методов класса
__numberOfFloors = None
def __init__(self):
self.__numberOfFloors = 0
print('Подготовлена строительная площадка')
def __len__(self):
return self.__numberOfFloors
def __del__(self):
print('Строение уничтожено')
def getNumberOfFloors(self):
return self.__numberOfFloors
def setNewNumberOfFloors(self, floors):
if self.isValidFloorNumberInput(floors):
self.__numberOfFloors = floors
return True
return False
def isValidFloorNumberInput(self, floorNumber):
# Номер этажа или число этажей не должны быть отрицательными
if floorNumber >= 0:
return True
return False
# Формирует число этажей прописью
def spellNumberOfFloors(self):
if self.__numberOfFloors == 0:
return 'есть только основание'
lastDigit = self.__numberOfFloors % 10
spellTemplate = f'{self.__numberOfFloors} этаж'
# 1 этаж
if lastDigit == 1 and self.__numberOfFloors != 11:
return spellTemplate
# 2, 3, 4 этажа
elif 2 <= lastDigit <= 4 and not 12 <= self.__numberOfFloors <= 14 :
return f'{spellTemplate}а'
# N этажей (во всех остальных случаях)
return f'{spellTemplate}ей'
class ResizableBuilding(Building):
'''
Строение, способное на лету изменять (достраивать недостающее или уничтожать лишнее) число этажей
'''
def __init__(self, floorBuilder):
super().__init__()
self.builder = floorBuilder
def setNewNumberOfFloors(self, floors):
# Проверяем корректность значения аргумента
if not self.isValidFloorNumberInput(floors):
return False
currentFloorCount = self.getNumberOfFloors()
# Кол-во этажей без изменений
if floors == currentFloorCount:
return False
# Этажей становится БОЛЬШЕ, чем есть сейчас
if abs(floors) > abs(currentFloorCount):
super().setNewNumberOfFloors(
self.builder.buildNewFloors(self.getNumberOfFloors(), floors - currentFloorCount)
)
# Этажей становится МЕНЬШЕ, чем есть сейчас
else:
super().setNewNumberOfFloors(
self.builder.destroyUnusedFloors(self.getNumberOfFloors(), currentFloorCount - floors)
)
# Число этажей изменилось
return True
class FloorBuilder:
'''
Бригада строителей абстрактных этажей
'''
def __init__(self, **kwargs):
self.floorBuildMessage = kwargs['floorBuildMessage']
self.floorDestroyMessage = kwargs['floorDestroyMessage']
self.floorNumberSign = kwargs['floorNumberSign']
def buildNewFloors(self, currentFloorCount, numberOfFloorsToAdd):
for newFloorNumber in range(numberOfFloorsToAdd):
print(self.floorBuildMessage, (currentFloorCount + newFloorNumber + 1) * self.floorNumberSign)
return currentFloorCount + numberOfFloorsToAdd
def destroyUnusedFloors(self, currentFloorCount, numberOfFloorsToDestroy):
for destroyedFloorNumber in range(numberOfFloorsToDestroy):
print(self.floorDestroyMessage, (currentFloorCount - destroyedFloorNumber) * self.floorNumberSign)
return currentFloorCount - numberOfFloorsToDestroy
class House(ResizableBuilding):
'''
Многоэтажный жилой дом в комплекте с бригадой строителей,
автоматически подстраивающих его под желаемые размеры
'''
def __init__(self):
super().__init__(
FloorBuilder(
floorBuildMessage='Быстренько достраиваем этаж',
floorDestroyMessage='Превращаем в прах этаж',
floorNumberSign=1
)
)
# Переопределение данного метода требуется для перехвата попыток изменения
# числа этажей втихаря, т.е. минуя этап их строительства.
def __setattr__(self, key, value):
# Перехватываем попытки изменения ключевого свойства объекта в обход интерфейса класса
if key == 'numberOfFloors':
if super().setNewNumberOfFloors(value):
print('Теперь у дома', self.spellNumberOfFloors())
else:
print('У дома по прежнему', self.spellNumberOfFloors())
# Для изменения всех остальных свойств объекта вызываем соответствующий метод базового класса
else:
super().__setattr__(key, value)
# Представление объекта в виде строки
def __str__(self):
return f'Дом, у которого {self.spellNumberOfFloors()}'
def __del__(self):
print('Дом снесен')
super().__del__()
def setNewNumberOfFloors(self, floors):
self.numberOfFloors = floors
class Bunker(ResizableBuilding):
'''
Многоуровневый бункер в комплекте с бригадой землекопов,
автоматически подстраивающих его под желаемые размеры
'''
def __init__(self):
super().__init__(
FloorBuilder(
floorBuildMessage = 'Бодро копаем этаж',
floorDestroyMessage = 'Заваливаем грунтом этаж',
floorNumberSign = -1
)
)
# Переопределение данного метода требуется для перехвата попыток изменения
# числа этажей втихаря, т.е. минуя этап их строительства.
def __setattr__(self, key, value):
# Перехватываем попытки изменения ключевого свойства объекта в обход интерфейса класса
if key == 'numberOfFloors':
if super().setNewNumberOfFloors(value):
print('Теперь у бункера', self.spellNumberOfFloors())
else:
print('У бункера по прежнему', self.spellNumberOfFloors())
# Для изменения всех остальных свойств объекта вызываем соответствующий метод базового класса
else:
super().__setattr__(key, value)
# Представление объекта в виде строки
def __str__(self):
return f'Бункер, у которого {self.spellNumberOfFloors()}'
def __del__(self):
print('Бункер закопан')
super().__del__()
def setNewNumberOfFloors(self, floors):
self.numberOfFloors = floors
heading("Сначала действуем строго по ТЗ, т.е. строим дом")
print()
narrative("Решили мы построить дом...")
house = House()
print(house)
narrative("Пять этажей воздвигли в нём.")
house.setNewNumberOfFloors(5)
narrative("Но тень от стен на двор легла,\n"
"и этажей в нём стало два...")
house.setNewNumberOfFloors(2)
narrative("Тут ипотечный бум настал,\n"
"Равшан свой инструмент достал.\n"
'Насяльникэ сказал: "Вперёд!"\n'
"Дом превратился в небоскрёб.")
house.setNewNumberOfFloors(120)
narrative("Вдруг дунул свежий ветерок,\n"
"Качнулся дом и на бок лёг.\n"
"Труд светлых дней и тьмы ночей -\n"
"Теперь лишь груда кирпичей.")
house.setNewNumberOfFloors(0)
narrative("Ноль этажей иль дома нет.\n"
"Как ни скажи, а смысл равен.\n"
"Признаемся, друзья, теперь\n"
"У нас всего лишь есть фундамент.")
house.setNewNumberOfFloors(0)
narrative("Начнем мы с чиатого листа,\n"
"И уничтожим все былое...")
del house
narrative("Решили мы построить дом.")
house = House()
narrative("Теперь мы действуем с умом.\n"
"Джамшут нам быстро возведёт\n"
"Тринадцать этажей на счастье!")
house.setNewNumberOfFloors(13)
print(house)
narrative("А теперь прозаично пытаемся напрямую изменить свойство объекта.")
house.numberOfFloors = -1 # Ошибочный ввод кол-ва этажей не приведет к изменению состояния объекта
house.numberOfFloors = 0 # Это даст тот же результат, что и вызов setNewNumberOfFloors(0)
print(house)
print()
heading("Теперь построим дом наоборот, т.е. выкопаем бункер")
print()
narrative("Во глубине сибирских руд\n"
"Решили выкопать мы бункер\n"
"Не пропадет наш скорбный труд\n"
"И может сами будем целы...")
bunker = Bunker()
print(bunker)
narrative("Копали бункер вчетвером:\n"
"Иван, Василий, лом, лопата")
bunker.setNewNumberOfFloors(10)
narrative("Был результат наш - о-го-го!")
print('Выкопано', len(bunker), 'этажей!!!')
narrative("И даже мы перестарались.")
bunker.setNewNumberOfFloors(2)
narrative("Потом приехал Николай\n"
"На экскаваторе японском\n"
"Ему сказали закопать\n"
"Всё наше чудное творенье.")
bunker.setNewNumberOfFloors(0)
narrative("Ну и т.д.")
bunker.numberOfFloors = -5
bunker.numberOfFloors = 5
print(bunker)
narrative("\nНа этом всё...")