Python создает экземпляры всех классов в модуле

Я работаю над текстовой приключенческой игрой, и у меня есть модуль, в котором есть все классы действий, например Move(Action), Look(Action). Мне нужен метод создания экземпляров всех классов в модуле, которые являются подклассом класса Action, в список, подобный этому:

actions = [Move(), Look()]

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


person Syphon    schedule 01.01.2016    source источник
comment
Я уверен, что вы сможете придумать, как создать их все оттуда!   -  person jonrsharpe    schedule 01.01.2016


Ответы (1)


Решение

Это работает:

class Action:
    pass

class Move(Action):
    pass

class Look(Action):
    pass


actions = []
global_objs = list(globals().items())

for name, obj in global_objs:
    if obj is not Action and isinstance(obj, type) and issubclass(obj, Action):
        actions.append(obj())
print(actions)

печатает:

[<__main__.Move object at 0x101916ba8>, <__main__.Look object at 0x101916be0>]

Шаги

Сначала мы получаем все имена объекта в текущем модуле:

global_objs = list(globals().items())

Нам нужно преобразовать в список, потому что в Python 3 items() возвращает объект dictview, который отражает изменения в нижележащем словаре. Поскольку мы работаем в одном модуле, определение новых объектов изменит этот словарь. Преобразование в список решает эту проблему.

Далее проходим по всем объектам. Чтобы стать подклассом Action, им необходимо выполнить три условия:

  1. obj is not Action- Поскольку Action является подклассом самого себя, нам нужно отфильтровать его.

  2. isinstance(obj, type) - Объект должен быть классом. В противном случае проверка в соответствии с 3. будет невозможна.

  3. issubclass(obj, Action) - Наконец, мы можем провести тест нашего подкласса.

Теперь мы можем создать экземпляры всех отфильтрованных классов и добавить их в наш список:

actions.append(obj())

Укороченная версия

Если вы уверены, что все классы определены в одном модуле или даже хотите, чтобы все подклассы были распределены по нескольким модулям, это будет намного короче:

>>> actions = [obj() for obj in Action.__subclasses__()]
>>> actions
[<__main__.Move at 0x10fc14fd0>, <__main__.Look at 0x10fc14668>]
person Mike Müller    schedule 01.01.2016
comment
for obj in Action.__subclasses__() сэкономит вам много хлопот ... - person jonrsharpe; 01.01.2016
comment
@jonrsharpe Хорошее замечание. Но он найдет все подклассы; не только это в модуле. По-прежнему нужно будет их отфильтровать. - person Mike Müller; 01.01.2016
comment
Хороший момент, но OP говорит, что все они в одном модуле - person jonrsharpe; 01.01.2016
comment
Добавил вариацию. Действительно, намного короче. - person Mike Müller; 01.01.2016