Подкласс Python, который принимает суперкласс в качестве аргумента при создании экземпляра? - PullRequest
0 голосов
/ 10 мая 2019

Я пытаюсь создать класс-оболочку в Python со следующим поведением:

  • Он должен принимать в качестве аргумента существующий класс, от которого он должен наследовать все методы и атрибуты
  • Методы класса-обертки должны иметь возможность использовать Python super () для доступа к методам суперкласса (переданного в качестве аргумента)

Из-за моего второго требования я думаю, что решения здесь будет недостаточно (и в любом случае у меня возникают отдельные проблемы, связанные с копированием некоторых методов суперкласса, от которого я пытаюсь унаследовать).

Я пробовал это, но это не правильно ...

class A:
    def shout(self):
        print("I AM A!")

class B:
    def shout(self):
        print("My name is B!")

class wrapper:
    def __init__(self, super_class):
        ## Some inheritance thing here ##
        # I initially tried this but no success...
        super(super_class).__init__() # or similar?

    def shout(self):
        print('This is a wrapper')
        super().shout()

И это поведение, которое мне требуется ...

my_wrapper = wrapper(A)
my_wrapper.shout()
# Expected output: 
# > This is a wrapper
# > I AM A

my_wrapper = wrapper(B)
my_wrapper.shout()
# Expected output: 
# > This is a wrapper
# > My name is B!

Является ли наследование правильным подходом, если да, я нюхаю в правильном направлении? Любая помощь приветствуется, спасибо:)

Изменить для контекста:

Я собираюсь создать несколько оболочек, чтобы все мои модели ML имели одинаковый API. Как правило, модели из одного и того же пакета (например, sklearn) имеют одинаковый API и должны иметь возможность оборачиваться одной и той же оболочкой. При этом я хочу изменить / добавить функциональность к существующим методам в этих моделях, сохранив то же имя метода.

Ответы [ 2 ]

0 голосов
/ 17 мая 2019

Итак, в конце концов я пошел на функцию. Мое окончательное решение:

class A:
    def shout(self):
        print("I AM A!")

class B:
    def shout(self):
        print("My name is B!")

def wrap_letter_class(to_wrap):

    global letterWrapper

    class letterWrapper(to_wrap):
        def __init__(self):
            super().__init__()

        def shout(self):
            print('This is a wrapper')
            super().shout()

        def __getstate__(self):
            # Add the wrapper to global scope before pickling
            global letterWrapper
            letterWrapper = self.__class__
            return self.__dict__

    return letterWrapper()

Который производит желаемое поведение ...

In [2]: wrapped = wrap_letter_class(A)

In [3]: wrapped.shout()
This is a wrapper
I AM A!

In [4]: wrapped = wrap_letter_class(B)

In [5]: wrapped.shout()
This is a wrapper
My name is B!

Что-то не упомянутое в моем первоначальном вопросе состояло в том, что я намеревался выбрать свой пользовательский класс, это невозможно, если класс не определен в глобальной области видимости, следовательно, __getstate__ и глобальные добавления.

Спасибо!

0 голосов
/ 10 мая 2019

Если обертка должна быть классом, то здесь композиционное решение подошло бы гораздо лучше.

Имейте в виду, что я превратил shout методы в staticmethod, потому что в вашем примере вы передаете классwrapper.shout, не экземпляр.

class A:
    @staticmethod
    def shout():
        print("I AM A!")


class B:
    @staticmethod
    def shout():
        print("My name is B!")


class wrapper:
    def __init__(self, super_class):
        self._super_class = super_class

    def __getattr__(self, item):
        try:
            return self.__dict__[item].__func__
        except KeyError:
            return self._super_class.__dict__[item].__func__

    def a_wrapper_method(self):
        print('a wrapper attribute can still be used')


my_wrapper = wrapper(A)
my_wrapper.shout()

my_wrapper = wrapper(B)
my_wrapper.shout()

my_wrapper.a_wrapper_method()

Выходы

This is a wrapper
I AM A!
This is a wrapper
My name is B!
a wrapper attribute can still be used
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...