Как мне организовать свои функции с помощью pyparsing?
-
18-09-2019 - |
Вопрос
Я анализирую файл с помощью Python и пипарсинг (это файл отчета для PSAT в Matlab, но это не важно). здесь это то, что у меня есть до сих пор.Я думаю, что это беспорядок, и хотел бы получить совет, как его улучшить.В частности, как мне организовать определения грамматики с помощью pyparsing?
Должен ли я объединить все определения грамматики в одну функцию?Если да, то это будет одна огромная функция.Если нет, то как мне его разбить.На данный момент я разбил его на разделы файла.Стоит ли создавать множество функций, которые вызываются из одного места только один раз?Ни то, ни другое мне не кажется правильным.
Должен ли я поместить весь свой входной и выходной код в отдельный файл для других функций класса?Это сделало бы цель класса намного яснее.
Мне также интересно узнать, есть ли более простой способ проанализировать файл, выполнить некоторые проверки работоспособности и сохранить данные в классе.Кажется, я трачу на это много времени.
(Я приму ответы это достаточно хорошо или используйте X вместо pyparsing если люди согласятся)
Решение
Я мог бы пойти любым путем, используя один большой метод для создания вашего парсера или метода.делайте это поэтапно, как вы это делаете сейчас.
Я вижу, что вы определили несколько полезных вспомогательных утилит, таких как slit («подавить литерал», я полагаю), stringtolits и decimaltable.Мне это кажется хорошим.
Мне нравится, что вы используете имена результатов, они действительно повышают надежность вашего кода после анализа.Я бы рекомендовал использовать форму ярлыка, добавленную в pyparsing 1.4.7, в которой вы можете заменить
busname.setResultsName("bus1")
с
busname("bus1")
Это может немного разгрузить ваш код.
Я бы просмотрел ваши действия по анализу, чтобы увидеть, где вы используете числовые индексы для доступа к отдельным токенам, и вместо этого вернулся бы и назначил имена результатов.Вот один случай, когда GetStats возвращает (ngroup + sgroup).setParseAction(self.process_stats)
.Process_stats имеет такие ссылки, как:
self.num_load = tokens[0]["loads"]
self.num_generator = tokens[0]["generators"]
self.num_transformer = tokens[0]["transformers"]
self.num_line = tokens[0]["lines"]
self.num_bus = tokens[0]["buses"]
self.power_rate = tokens[1]["rate"]
Мне нравится, что вы сгруппировали значения и статистику, но давайте дадим им имена, например «сеть» и «солн».Затем вы могли бы написать этот код действия синтаксического анализа как (я также преобразовал в более удобную для чтения нотацию атрибута объекта вместо нотации элемента dict):
self.num_load = tokens.network.loads
self.num_generator = tokens.network.generators
self.num_transformer = tokens.network.transformers
self.num_line = tokens.network.lines
self.num_bus = tokens.network.buses
self.power_rate = tokens.soln.rate
И еще вопрос по стилю:почему вы иногда используете явный конструктор And вместо оператора «+»?
busdef = And([busname.setResultsName("bus1"),
busname.setResultsName("bus2"),
integer.setResultsName("linenum"),
decimaltable("pf qf pl ql".split())])
Так же легко пишется:
busdef = (busname("bus1") + busname("bus2") +
integer("linenum") +
decimaltable("pf qf pl ql".split()))
В целом, я думаю, это примерно нормально для файла такой сложности.У меня есть похожий формат (собственный, к сожалению, поэтому не может быть передан), в котором я собирал код по частям, как у вас, но в один большой метод, примерно так:
def parser():
header = Group(...)
inputsummary = Group(...)
jobstats = Group(...)
measurements = Group(...)
return header("hdr") + inputsummary("inputs") + jobstats("stats") + measurements("meas")
Конструкции Group особенно полезны в таких больших анализаторах, как этот, поскольку они позволяют создать своего рода пространство имен для имен результатов в каждом разделе анализируемых данных.