Унаследовать свойства от уже созданного родительского класса в дочернем классе - PullRequest
0 голосов
/ 18 марта 2019

Я застрял в этом вопросе о наследовании классов, и я не смог найти правильный путь вперед. У меня есть базовый класс:

class Foo:
    """ Parent class. """

    def __init__(self,a,b):
        self.a = a
        self.b = b

    def product(self):
        return self.a * self.b

Этот класс содержит информацию, которую я загрузил из некоторого файла данных. Я хочу генерировать различные виды информации, связанной с этими данными, используя свойства класса для хранения этой информации. Например, если бы я хотел создать отчет, который сообщал бы мне отношения a и b, я хотел бы создать что-то вроде:

class Bar(Foo):
    """ Child class. """

    def __init__(self,foo_object):

        # What I want to avoid:
        self.a = foo_object.a
        self.b = foo_object.b

    def quotient(self):
        return self.a / self.b

Очевидно, что в моем реальном приложении есть еще много свойств класса. Назначение всех свойств объекта Foo в новый объект Bar становится очень утомительным.

Есть ли более элегантный способ "расширить" объект Foo в объект Bar после того, как объект Foo уже создан?

EDIT:

Извините, если я недостаточно четко изложил свою цель; Я вижу, что есть некоторая путаница в том, что я прошу. Я уже создал объект Foo с рядом свойств. Я хочу создать дочерний класс Foo с именем Bar, позже, , который содержит эти свойства, но также некоторые дополнительные свойства, специфичные для одной "области" моего приложения.

Итак, я хочу иметь возможность передавать уже созданный экземпляр объекта Foo и передавать значения его свойств в идентичные свойства в Bar, не делая это вручную по элементам.

Я верю, что ответ Флоба - это то, что я ищу. Спасибо!

Ответы [ 4 ]

0 голосов
/ 18 марта 2019

Вы можете наследовать информацию напрямую, инициируя родительский класс внутри дочернего класса. Создав экземпляр родительского класса, вы можете получить доступ ко всем его свойствам с помощью vars(object), который вернет словарь всех свойств, связанных с объектом. Например, допустим, у вас есть класс Foo:

class Foo:
    def __init__(self, a, b):
        self.a = a
        self.b = b

и test_parent является экземпляром этого класса.

test_parent = Foo(a='Hello', b='World')

Теперь при создании дочернего класса Bar сделайте это следующим образом:

class Bar(Foo):
    def __init__(self, foo_object):
        a, b = vars(foo_object).values()  #get all properties of parent class object
        Foo.__init__(self, a, b)  # initiate parent class
    def say_hello(self):
        print('{} {}'.format(self.a, self.b))

Создайте экземпляр класса Bar и вызовите say_hello:

test_child = Bar(test_parent)
test_child.say_hello()

Выход:

"Hello World"
0 голосов
/ 18 марта 2019

Можно изменить класс объекта после его создания. Вместо того, чтобы распаковывать содержимое объекта в новый, вы меняете класс, который он использует для поиска методов:

class Foo:
    def __init__(self, a, b):
        self.a = a
        self.b = b

class Bar(Foo):
    def quotient(self):
        return self.a/self.b

f = Foo(1, 2)
f.__class__ = Bar
f.quotient()  # 0.5

Обычно это не нужно (я не рекомендую использовать его здесь). Вместо этого вы можете создать Bar объект напрямую:

b = Bar(1, 2)
b.quotient()

Bar наследует __init__ метод Foo, поэтому вам не нужно его переопределять.

Другой вариант - использовать функцию, которая не является методом:

def quotient(obj):
    return obj.a/obj.b

Теперь вы можете вычислять quotient(Foo(1,2)), даже если ваш объект Foo не знает о функции quotient.

0 голосов
/ 18 марта 2019

Класс может наследовать от базового класса, но объект не может наследоваться от другого объекта.Это может быть либо копия (возможно с дополнительными атрибутами), либо упаковка исходного объекта.Первый случай относится к стратегии истинного наследования (дочерний экземпляр должен быть экземпляром базового класса и должен инициализироваться сам), второй - для стратегии агрегации или сдерживания.

Но будьте осторожны, со вторым есть некоторые предостережения, в основном потому, что объект child не является экземпляром базового класса (isinstance(child, Foo) - false).Это означает, что здесь не существует единого размера, и вам придется выбрать один шаблон: наследование или агрегация.

0 голосов
/ 18 марта 2019

Я не уверен, что понимаю, что вы имеете в виду, когда "объект Foo уже создан".

Для инициализации атрибутов, определенных родительским классом, используйте это:

class Bar(Foo):
    """ Child class. """

    def __init__(self,a,b):
        super().__init__(a,b)

    def quotient(self):
        return self.a / self.b

Пусть метод __init__() суперкласса продолжает выполнять свою работу по инициализации a и b.

Обратите внимание, что b = B() создает только один объект, а не два.


В размещенном вами коде Bar.__init__(), кажется, принимает объект Foo в качестве одного из аргументов.Технически, это случай обертывания объекта Foo в объекте Bar - и если вы это делаете, на самом деле Bar нет необходимости быть дочерним классомFoo:

class Bar:
    """ Wrapper class. """

    def __init__(self, foo_object):
        self.foo_object = foo_object

    def quotient(self):
        return self.foo_object.a / self.foo_object.b
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...