Как поменять класс объекта на его сабкласс сохраняя все атрибуты и инстанции?
Подскажите как без использования каких-либо библиотек и внешних методов и функций поменять класс объекта сохраняя все его бывшие инстанции.
Код снизу это представление иерархии компании, класс работников (Worker), класс начальников (Boss) и класс корпорации(Corporation). У Boss и Worker все атрибуты кроме одного идентичные. Как поменять работника на начальника (и наоборот) сохраняя все эти атрибуты и место в иерархии. Подскажите как именно инцициализировать смену класса в методе promote_or_demote(), так чтобы все сохранилось и внутри иерархии произошли изменения?
class Worker:
""" self.subworkers это список прямых подчиненных работников. """
id: int
position: str
grade: int
subworkers: List[Worker]
def __init__(self, id: int, workplace: str, age: int, position: str, grade: int) -> None:
self.id = id
self.workplace = workplace
self.age = age
self.position = position
self.grade = grade
self.subworkers = []
class Boss(Worker):
""" Класс наследует все инстанции Worker."""
_company: str
def __init__(self, id: int, workplace: str, age: int, position: str, grade: int,
company: str) -> None:
Worker.__init__(self, id, workplace, age, position, grade)
self._company = company
class Corporation:
"""Класс корпорации"""
_leader: Optional[Worker]
def __init__(self, leader: Optional[Worker] = None) -> None:
self._leader = leader
def promote_or_demote(self, id: int, company_name: Optional[str] = None) -> Worker:
""" Поменяйте тип рабочего с этим <id>.
Повысьте Worker до Boss или понизьте Boss до Worker. Все инстанции должны сохранится.
Верните нового работника/босса.
Условие: Если <id> это id Boss'а, то company_name должно быть None """
Ответы (2 шт):
Я не знаю, можно ли так делать в плане правил кода, но чисто механически класс можно сменить путем замены атрибута __class__. При такой смене метод __init__ класса, на который вы сменили вызываться не будет
class A:
def print(self):
print(self.__class__)
def change_class(self):
self.__class__ = B
class B(A):
pass
obj = A()
obj.print()
obj.change_class()
obj.print()
Вывод:
<class '__main__.A'>
<class '__main__.B'>
class Worker:
def __init__(self, id_: int, workplace: str, age: int, position: str, grade: int) -> None:
self.id_ = id_
self.workplace = workplace
self.age = age
self.position = position
self.grade = grade
self.subworkers = []
def promote(self, comp):
return Boss(self.id_, self.workplace, self.age, self.position, self.grade, comp)
class Boss(Worker):
def __init__(self, id_: int, workplace: str, age: int, position: str, grade: int, company: str):
super().__init__(id_, workplace, age, position, grade)
self._company = company
def demote(self):
return Worker(self.id_, self.workplace, self.age, self.position, self.grade)
anyone = ... # Boss or Worker
anyone = anyone.demote() if isinstance(anyone , Boss) else anyone .promote(company_name)
Я вас натолкну на мысль, а вы уже её внедрите как вам нужно, так сложно понять что вы хотите.
Советы:
- id - зарезервированое слово в Python, используйте другое имя для атрибута
- Почитайте о super(), для вызова родительских функций используйте его.
- Не вызывайте магические методы напрямую(Worker.init), для них есть реализация правильная
- Все атрибуты для будущих обьектов обьявляются только внутри init, вне init вы обьявляете атрибуты класса, почитайте об этом, также посмотрите на встроену либу dataclasses
- Если метод или функция ничего не возвращает можете не писать для неё тайпинг.