Итак, я столкнулся с этой проблемой, это сложно объяснить, поэтому я попробую провести аналогию с пиццей:
У нас есть следующие классы:
class Storage:
# this seems like i should use a dict, but let's assume there is more functionality to it
def __init__(self, **kwargs):
self.storage = kwargs
# use like: Storage(tomato_cans=50, mozzarella_slices=200, ready_dough=20)
def new_item(self, item_name: str, number: int):
self.storage[item_name] = number
def use(self, item_name: str, number: int):
self.storage[item_name] = self.storage.get(item_name) - number
def buy(self, item_name: str, number: int):
self.storage[item_name] = self.storage.get(item_name) + number
class Oven:
def __init__(self, number_parallel):
# number of parallel pizzas possible
self.timers = [0] * number_parallel
def ready(self):
return 0 in self.timers
def use(for_mins):
for i, timer in enumerate(self.timers):
if timer == 0:
self.timers[i] = for_mins
break
def pass_time(mins):
for i in range(len(self.timers)):
self.timers[i] = max(0, self.timers[i]-mins)
class Pizza:
def __init__(self, minutes=6, dough=1, tomato_cans=1, mozzarella_slices=8, **kwargs):
self.ingredients = kwargs
self.ingredients['dough'] = dough
self.ingredients['tomato_cans'] = tomato_cans
self.ingredients['mozzarella_slices'] = mozzarella_slices
self.minutes = minutes
def possible(self, oven, storage):
if not oven.ready():
return False
for key, number in self.ingredients:
if number > storage.storage.get(key, 0):
return False
return True
def put_in_oven(self, oven, storage):
oven.use(self.minutes)
for key, number in self.ingredients:
storage.use(key, number)
Мы могу сделать пиццу сейчас, например:
storage = Storage()
oven = Oven(2)
margherita = Pizza()
prosciutto = Pizza(ham_slices=7)
if margherita.possible():
margherita.put_in_oven()
storage.new_item('ham_slices', 20)
if prosciutto.possible():
prosciutto.put_in_oven()
А теперь мой вопрос (извините, если это было слишком подробно):
Могу ли я создать экземпляр Pizza и изменить его метод put_in_oven?
Как, например, пицца, где вам нужно сначала приготовить немного овощей или проверить, подходит ли это время для возможного метода.
Я представляю что-то вроде:
vegetariana = Pizza(paprika=1, arugula=5) # something like that i'm not a pizzaiolo
def vegetariana.put_in_oven(self, oven, storage):
cook_vegetables()
super().put_in_oven() # call Pizza.put_in_oven
Надеюсь, этот вопрос не слишком громоздкий!
Редактировать:
Итак, давайте предположим, что мы будем использовать наследование :
class VeggiePizza(Pizza):
def put_in_oven(self, oven, storage):
self.cut_veggies()
super().put_in_oven(oven, storage)
def cut_veggies(self):
# serves purpose of explaining
# analogy has its limits
pass
class SeasonalPizza(Pizza):
def __init__(self, season_months, minutes=6, dough=1, tomato_cans=1, mozzarella_slices=8, **kwargs):
self.season_months # list of month integers (1 - 12)
super().__init__()
def possible(self, oven, storage):
return super().possible(oven, storage) and datetime.datetime.now().month in self.season_months
Моя проблема с этим заключается в том, что я могу приготовить сезонную вегетарианскую ie пиццу или другие подклассы или снова разные их комбинации или даже подклассы, которые могут обслуживать только один экземпляр.
Например, для PizzaAmericano
(с картофелем фри сверху) я бы использовал подкласс, такой как VeggiePizza и pu t fry_french_fries()
перед super().put_in_oven()
, и я бы определенно не использовал этот подкласс для любого другого экземпляра, кроме pizza_americano
(в отличие от VeggiePizza
, где вы можете сделать различную вегетарианскую пиццу).
Это нормально? Мне кажется, что это противоречит принципу классов.
РЕДАКТИРОВАТЬ:
Хорошо, благодаря вашим ответам и этот рекомендуемый вопрос Я сейчас знать, как добавить / изменить метод экземпляра. Но прежде чем закрыть этот вопрос как дубликат; Это вообще что-то, что совершенно нормально или, скорее, рекомендуется против ? Я имею в виду, что это кажется неестественным из-за простоты его природы, имея метод, специфицирующий экземпляр c, точно так же, как переменные, специфицирующие c переменные.