#python #code-generation
#python #генерация кода
Вопрос:
Допустим, у меня есть модуль python foo.py который содержит:
class Foo(object):
def __init__(self):
pass
Затем я хочу разобрать этот скрипт и внедрить метод в каждый из его классов, переписав его примерно так:
class Foo(object):
def __init__(self):
pass
def my_method(self):
pass # do some stuff here
Я заметил, что в python 2.6 есть ast
модуль, который можно было бы использовать для этого, но, к сожалению, мне нужно сделать это в python 2.5. Приветствуются любые предложения.
Комментарии:
1. Вы на самом деле анализируете исходные текстовые файлы Python .py и хотите записать . py-файлы, или вы говорите об изменении определений классов в памяти времени выполнения?
2. @dkamins разбирает исходные текстовые файлы Python .py и хочет записать. py-файлы
Ответ №1:
Я понимаю, что вы пытаетесь сделать, но если ваш исходный код достаточно прост, возможно, вы могли бы вообще пропустить весь синтаксический анализ и обратную запись и просто запустить регулярное выражение?
Что-то вроде:
re.sub('^classs (w ):s*n', 'class \1:n%s' % method_source, file_source, flags=re.M)
Просто сделайте правильный отступ..
Комментарии:
1. Пример приведен просто для того, чтобы указать на то, чего я пытаюсь достичь. Фактический исходный код, который я пытаюсь отредактировать, представляет собой гораздо более сложный скрипт, поэтому я бы не стал полагаться на простой синтаксический анализ строки. Например, посмотрев на ваше регулярное выражение, я мог бы использовать слово ‘class’ как часть многострочного комментария, и в этом случае регулярное выражение завершилось бы ошибкой
2. На самом деле существует не так много способов для сбоя. Вложенные классы не будут исправлены. У вас есть какой-нибудь? Должны ли они быть исправлены? Все, что произойдет с многострочным комментарием, окружающим класс, — это то, что этот класс тоже будет отредактирован. Если вам нужен реальный анализатор, вы могли бы использовать pyparsing и это грамматическое определение: pyparsing. wikispaces.com/file/view/pythonGrammarParser.py
3. Регулярное выражение не будет работать для классов нового стиля. И даже если вы это исправите, у вас может возникнуть ситуация, когда унаследованные классы распределяются по нескольким строкам. Вы могли бы исправить и это, но тогда результирующее регулярное выражение рисковало бы превратиться в чудовище.
Ответ №2:
У вас уже есть скрипт? Вы должны быть в состоянии исправить его прямо сейчас. Чтобы удовлетворить ваши текущие требования, было бы неплохо что-то вроде этого:
class Foo(object):
def my_method(self):
pass
В качестве альтернативы, вы могли бы определить my method
и добавить его в Foo
класс в качестве атрибута:
def my_method(self):
pass
Foo.my_method = my_method
#or
Foo.__dict__.my_method = my_method
Комментарии:
1. Я думаю, что он хочет добавлять их динамически во время выполнения и без указания имени каждого класса. Что-то вроде
for spam in foo.classes: spam.my_method = my_method
.2. Я думал о втором подходе. Это не будет работать так прямолинейно, как в вашем примере, но это будет работать при использовании нового модуля python ( docs.python.org/library/new.html ). Проблема в том, что сгенерированный скрипт будет довольно сложным для чтения, поэтому я бы предпочел что-то вроде вашего первого предложения, но я не знаю, как безопасно это сделать, не прибегая к построению синтаксического дерева, добавлению к нему узлов, а затем его перезаписи…
3. @Ioan вы должны добавить ответ на свой вопрос и позволить другим проголосовать за него. Это звучит как разумный подход.
4. @Ioan Если вы перепишете все свое синтаксическое дерево, вы можете потерять комментарии (которые не включены в стандартный анализатор Python) и форматирование.
5. @Gurgeh Да, меня на самом деле не волнует потеря комментариев. Меня беспокоит только то, чтобы выходной скрипт функционировал в ожидаемом режиме.
Ответ №3:
Решением было бы:
class Foo(object):
def __init__(self):
pass
import new
def some_func(self):
print "foobar"
Foo.my_method = new.instancemethod(some_func, None, Foo)
Проблема в том, что мне не нравится добавлять определения нового метода в конец файла. Я бы хотел, чтобы классы в сгенерированном скрипте выглядели следующим образом:
class Foo(object):
def __init__(self):
pass
def my_method(self):
print "foobar"
но не могу найти решение для этого без построения, модификации и последующей обратной записи дерева синтаксиса.