2014-10-03 3 views
2

По множеству причин я нахожусь в положении импорта многих модулей python и хочу перебирать каждый из классов в модуле.Цитирование через импортированные классы в python

from capacity_hdd_parser import CapacityHDDParser 
from capacity_ssd_parser import CapacitySSDParser 
from checksum_parser import ChecksumParser 
. 
. 
. 

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

parsers = [CapacityHDDParser, CapacitySSDParser, ChecksumParser] 
for parser in parsers: 
    parser_instance = parser() 
    data_returned = parser_instance.parse(logset_path) 
    # Do a bunch of post processing here. 

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

+0

hack: 'for Parser in base_class .__ подклассы __()' – jfs

+1

Если вы не можете найти совершенно другой метод достижения своей общей цели, я бы посоветовал вам придерживаться вашего текущего метода. Это кажется утомительным и подверженным ошибкам, но мета-программирование и манипулирование переменными и идентификаторами, как если бы они были данными, могут быть еще более рискованными. Ваш текущий подход кажется простым и читаемым, поэтому вы можете просто придерживаться его. Это похоже на проблему [XY Problem] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – skrrgwasme

+0

@SLawson Моя последняя проблема заключается в том, что время запуска python больше времени для запуска парсеров, но такое обсуждение (я считаю) выходит за рамки вопроса SO. – AlexLordThorsen

ответ

3

Если вы не нуждаетесь в них в глобальном пространстве имен, вы можете использовать importlib.import_module.

from importlib import import_module 

for module_name, class_name in (('capacity_hdd_parser', 'CapacityHDDParser'), 
           ('capacity_ssd_parser', 'CapacitySSDParser'), 
           ('checksum_parser', 'ChecksumParser')): 
    data_returned = getattr(import_module(module_name), class_name)().parse(logset_path) 
    # Other processing here 

Возможно, вы также захотите объединить свои классы парсеров в один пакет. Это сделало бы этот подход более сухим, а также, вероятно, более питоническим. Один класс для файла обычно избыточно/многословен в Python.

+0

+1 для декларативного подхода. –

+0

@silas ray ..why у вас используется дополнительный '()' on 'getattr (import_module (имя_пакета), class_name)(). Parse (longest_path)' –

+0

Чтобы создать экземпляр объекта парсера. –

2

Дети, не пытайтесь повторить это дома:

parsers = [v for (k, v) in locals().items() 
      if k.endswith('Parser')] 

Вы можете сделать его немного безопаснее с лучшим условием испытания.

[обновление]

декларативный подход Сила является безопасной ставкой:

PARSERS = { 
    'capacity_hdd_parser': 'CapacityHDDParser', 
    'capacity_ssd_parser': 'CapacitySSDParser', 
    'checksum_parser': 'ChecksumParser', 
    ... 
} 

def load_parser(module, parser): 
    return getattr(importlib.import_module(module), parser) 

parsers = [load_parser(*item) for item in PARSERS.items()] 

еще лучше, вы можете заменить PARSERS Dict с config file.

+2

Я думаю, что ваше предупреждение имеет обратную сторону: это прекрасно, когда можно попробовать дома.Не делайте этого в корпоративной среде. – skrrgwasme

+0

Так что это возвращает все классы, которые меня интересуют. В чем проблема с этим ответом? – AlexLordThorsen

+1

Проблема в том, что если кто-то еще вводит переменную, заканчивающуюся «Parser» в пространстве имен, могут возникнуть неожиданные результаты. Таким образом, это скрытая ловушка в миллионном корпоративном приложении LoC, но для ad-hoc кода выброса, я склонен побаловать себя. –

0
for Parser in get_registered_parsers(): 
    data = Parser().parse(logset_path) 

Определение get_registered_parsers() любыми средствами, включая черной магии, например, Setuptools entry_points или yapsy (plugin architecture) или азбуки (явное register() функции) и т.д.

Смежные вопросы