Если у меня уже есть экземпляр суперкласса, как я могу создать из него экземпляр дочернего класса?

Как правильно наследовать данные из экземпляра суперкласса? Например, рассмотрим что-то, что я могу заставить работать, но его поведение сбивает с толку:

from dataclasses import dataclass
from typing import Self

@dataclass
class SuperClass:
  hello: int
  world: int

@dataclass
class ChildClass(SuperClass):
  kitty: int

  @classmethod
  def from_super(cls, s: SuperClass, kitty: int) -> Self:
    x = cls(s, kitty=kitty)
    return x

Теперь посмотрим, работает ли это:

super_instance = SuperClass(0, 1)
child = ChildClass.from_super(super_instance, 2)
child

Это производит вывод:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[48], line 1
----> 1 ChildClass.from_super(super_instance, 2)

Cell In[46], line 15
     13 @classmethod
     14 def from_super(cls, s: SuperClass, kitty: int) -> Self:
---> 15     x = cls(s, kitty=kitty)
     16     return x

TypeError: ChildClass.__init__() missing 1 required positional argument: 'world'

Итак, как мне сделать это правильно, не записывая вручную каждый экземпляр переменной из суперкласса?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
76
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

В вашем примере вы, похоже, пытаетесь наследовать данные из экземпляра суперкласса (SuperClass) в подкласс (ChildClass). Однако у вашего подхода есть некоторые проблемы, в первую очередь из-за того, как в Python работают декоратор dataclass и наследование.

Чтобы правильно наследовать данные от экземпляра суперкласса, вам необходимо использовать наследование. Давайте изменим ваш код, чтобы продемонстрировать правильный способ сделать это с помощью наследования:

  1. Сделайте ChildClass наследником SuperClass.
  2. Используйте функцию super() для инициализации части суперкласса.
from dataclasses import dataclass

from typing import Self

@dataclass
class SuperClass:
    hello: int
    world: int

@dataclass
class ChildClass(SuperClass):
    kitty: int

    @classmethod
    def from_super_wtf(cls, s: SuperClass, kitty: int) -> Self:
        x = cls(hello=s.hello, world=s.world, kitty=kitty)
        return x

    @classmethod
    def from_super_works(cls, s: SuperClass, kitty: int) -> Self:
        x = cls(hello=s.hello, world=s.world, kitty=kitty)
        return x

    @classmethod
    def from_super_sane(cls, s: SuperClass, kitty: int) -> Self:
        x = cls(hello=s.hello, world=s.world, kitty=kitty)
        return x

# Testing the code
super_instance = SuperClass(0, 1)
child = ChildClass.from_super_works(super_instance, 2)
child_wtf = ChildClass.from_super_wtf(super_instance, 2)
child_sane = ChildClass.from_super_sane(super_instance, 2)

print(child)       # Expected: ChildClass(hello=0, world=1, kitty=2)
print(child_wtf)   # Expected: ChildClass(hello=0, world=1, kitty=2)
print(child_sane)  # Expected: ChildClass(hello=0, world=1, kitty=2)

В этом подходе ChildClass наследуется от SuperClass, что означает, что он также наследует атрибуты hello и world. При создании нового экземпляра

Я отредактировал свой вопрос, так как допустил опечатку и забыл сделать с наследством. Теперь это должно быть исправлено. Однако это все еще не работает так, как можно было бы ожидать. Кроме того, и это ключевой момент, я не хочу этого делать x = cls(hello=s.hello, world=s.world, kitty=kitty), потому что в моем суперклассе может быть много переменных, и я хотел бы автоматически наследовать их.

bzm3r 23.06.2024 22:57

В конечном итоге вы несете ответственность за «разборку» экземпляра суперкласса в форму, которую SuperClass.__init__ примет. Один из хрупких способов сделать это — просто распаковать s.__dict__ и использовать его в качестве аргументов ключевого слова. (Хрупкое, потому что, как правило, содержимое s.__dict__ не обязательно находится во взаимно однозначном соответствии с исходными аргументами, использованными для создания s.)

from dataclasses import dataclass
from typing import Self

@dataclass
class SuperClass:
  hello: int
  world: int

@dataclass
class ChildClass(SuperClass):
  kitty: int

  @classmethod
  def from_super(cls, s: SuperClass, kitty: int) -> Self:
    x = cls(**s.__dict__, kitty=kitty)
    return x
Ответ принят как подходящий
@classmethod
def from_super(cls, s: SuperClass, kitty: int) -> Self:
    x = cls(s, kitty=kitty)
    return x

Здесь, если вы не хотите явно перечислять все аргументы для cls, вместо передачи экземпляра s суперкласса вам нужно создать из s либо кортеж значений, которые можно передать в качестве позиционных аргументов *args, либо словарь параметров. имена и значения, которые вы можете передать в качестве аргументов ключевых слов **kwargs.

Поскольку вы используете простые классы данных, это легко:

Другие вопросы по теме