Как создать подкласс из строки, переданной суперклассу в python? - PullRequest
0 голосов
/ 22 апреля 2020

Для суперкласса с двумя (или многими) подклассами, для простоты, давайте назовем их Super, Sub1 и Sub2 соответственно. Я хотел бы создать экземпляры Sub1 и Sub2 следующим образом:

s1 = Super('Sub1')
s2 = Super('Sub2')

, т. Е. Передать имя подкласса в виде строк конструктору суперкласса.

Что-то, что пришло в голову определял переменную класса в Super с именами подклассов, и с помощью пары операторов if в конструкторе Super класса мог быть вызван соответствующий конструктор подкласса. Я не совсем уверен, сработает ли это, но мне это кажется грязным. Любые предложения о том, как решить эту проблему с помощью чистого и питонного подхода c, приветствуются.

Ответы [ 2 ]

0 голосов
/ 22 апреля 2020

Это требует переопределения Super.__new__, чтобы превратить его в фабричную функцию.

class Super:
    def __new__(cls, subclass_name, *args, **kwargs):
        for sc in cls.__subclasses__():
            if sc.__name__ == subclass_name:
                return super().__new__(sc, *args, **kwargs)
        raise ValueError("No such subclass")    


class Sub1(Super):
    pass


class Sub2(Super):
    pass


assert type(Super('Sub1')) is Sub1

Это требует дополнительной работы, чтобы позволить вам непосредственно определить подкласс (так как Sub1() вызовет Super.__new__, так как Sub1.__new__ не определено).

Поэтому я бы предпочел метод выделенного класса, который принимает имя класса, а не переопределяет __new__.

class Super:
    @classmethod
    def subclass_by_name(cls, name, *args, **kwargs):
        for sc in cls.__subclasses__():
            if sc.__name__ == name:
                return sc(*args, **kwargs)
        raise ValueError("No such subclass")


assert type(Super.subclass_by_name('Sub1')) is Sub1
0 голосов
/ 22 апреля 2020

Я не думаю, что это хорошая идея. Суперкласс не предназначен в качестве контейнера для конечного списка возможных подклассов, что в значительной степени идет вразрез с точкой наследования. Если бы я был тобой, я бы вместо этого создал простую фабрику, из которой я мог бы создавать нужные объекты, например:

class Fruit():
  ...

class Apple(Fruit):
  ...

class Pear(Fruit):
  ...


fruits = {
   "apple": Apple,
   "pear": Pear       
}

def make_fruit(name, **kwargs):
    return fruits[name](**kwargs)

apple = make_fruit("apple", colour="red")
pear = make_fruit("pear", size="small)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...