2009-09-01 3 views
10

У меня есть группа объектов, для которых я создаю класс, для которого я хочу сохранить каждый объект в виде собственного текстового файла. Я действительно хотел бы сохранить его как определение класса Python, которое подклассифицирует основной класс, который я создаю. Итак, я немного пошутил и нашел генератор кода Python на effbot.org. Я сделал некоторые эксперименты с ним, и вот что я придумал:Python generate Python

# 
# a Python code generator backend 
# 
# fredrik lundh, march 1998 
# 
# [email protected] 
# http://www.pythonware.com 
# 
# Code taken from http://effbot.org/zone/python-code-generator.htm 

import sys, string 

class CodeGeneratorBackend: 

    def begin(self, tab="\t"): 
     self.code = [] 
     self.tab = tab 
     self.level = 0 

    def end(self): 
     return string.join(self.code, "") 

    def write(self, string): 
     self.code.append(self.tab * self.level + string) 

    def indent(self): 
     self.level = self.level + 1 

    def dedent(self): 
     if self.level == 0: 
      raise SyntaxError, "internal error in code generator" 
     self.level = self.level - 1 

class Point(): 
    """Defines a Point. Has x and y.""" 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

    def dump_self(self, filename): 
     self.c = CodeGeneratorBackend() 
     self.c.begin(tab=" ") 
     self.c.write("class {0}{1}Point()\n".format(self.x,self.y)) 
     self.c.indent() 
     self.c.write('"""Defines a Point. Has x and y"""\n') 
     self.c.write('def __init__(self, x={0}, y={1}):\n'.format(self.x, self.y)) 
     self.c.indent() 
     self.c.write('self.x = {0}\n'.format(self.x)) 
     self.c.write('self.y = {0}\n'.format(self.y)) 
     self.c.dedent() 
     self.c.dedent() 
     f = open(filename,'w') 
     f.write(self.c.end()) 
     f.close() 

if __name__ == "__main__": 
    p = Point(3,4) 
    p.dump_self('demo.py') 

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

+0

Не используйте вкладки для отступа python, используйте пробелы :) –

+0

да, он устанавливает это как значение по умолчанию, но я перезаписал эту переменную w/4 пробела. – Jonathanb

ответ

22

Мы используем Jinja2 для заполнения шаблона. Это намного проще.

Шаблон очень похож на код Python с несколькими заменами {{something}}.

+0

В моем комментарии к Анону, я просто использую систему шаблонов. Я буду внимательно смотреть на Jinja, спасибо за подсказку! – Jonathanb

+2

есть ли пример? – KJW

+0

Это отличный способ сделать это! – specialscope

5

Это практически лучший способ генерации Python источник код. Однако вы также можете сгенерировать исполняемый код Python во время выполнения, используя библиотеку ast. (Я связан с версией Python 3, потому что она более способна, чем версия 2.x). Вы можете создать код с использованием абстрактного синтаксического дерева, а затем передать его compile(), чтобы скомпилировать его в исполняемый код. Затем вы можете использовать eval для запуска кода.

Я не уверен, есть ли удобный способ сохранить скомпилированный код для использования позже (т. Е. В файле .pyc).

+0

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

+0

Достаточно справедливо, я оставлю этот ответ здесь, если это полезно для кого-то другого с похожим вопросом. –

0

Из того, что, как я понимаю, вы пытаетесь сделать, я бы подумал об использовании отражения, чтобы динамически исследовать класс во время выполнения и генерировать вывод на основе этого. Существует хороший учебник по отражению (интроспекция А.К.А.) по адресу http://diveintopython3.ep.io/.

Вы можете использовать функцию dir(), чтобы получить список имен атрибутов данного объекта. Строка doc объекта доступна через атрибут __doc__. То есть, если вы хотите взглянуть на строку документации функции или класса, который вы можете сделать следующее:

>>> def foo(): 
... """A doc string comment.""" 
... pass 
... 
>>> print foo.__doc__ 
A doc string comment. 
+0

У меня есть куча планет, которые я хочу хранить каждый в качестве своих собственных текстовых файлов. Я не особенно привязан к их сохранению в качестве исходного кода на основе python, но я привязан к тому, чтобы сделать их доступными для человека. – Jonathanb

1

Я не уверен в том, что это особенно Pythonic, но вы можете использовать перегрузку операторов:

class CodeGenerator: 
    def __init__(self, indentation='\t'): 
     self.indentation = indentation 
     self.level = 0 
     self.code = '' 

    def indent(self): 
     self.level += 1 

    def dedent(self): 
     if self.level > 0: 
      self.level -= 1 

    def __add__(self, value): 
     temp = CodeGenerator(indentation=self.indentation) 
     temp.level = self.level 
     temp.code = str(self) + ''.join([self.indentation for i in range(0, self.level)]) + str(value) 
     return temp 

    def __str__(self): 
     return str(self.code) 

a = CodeGenerator() 
a += 'for a in range(1, 3):\n' 
a.indent() 
a += 'for b in range(4, 6):\n' 
a.indent() 
a += 'print(a * b)\n' 
a.dedent() 
a += '# pointless comment\n' 
print(a) 

Это, конечно, намного дороже, чем ваш пример, и я бы опасался слишком много метапрограмм, но это было веселое упражнение.Вы можете расширять или использовать это, как вы сочтете нужным; как насчет:

  • добавить метод записи и перенаправлять стандартный вывод на объект, чтобы напечатать прямо в файл сценарий
  • наследуемого от него настраивать вывод
  • добавляющих добытчиков атрибутов и сеттер

Было бы здорово услышать о том, что вы идете с :)

7

Просто прочитал свой комментарий к wintermute - то есть:

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

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

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

Преимущество просто выписывания данных (это может включать в себя информацию типа метки для удобства чтения, которую вы пропустили при ее чтении) заключается в том, что программисты, не являющиеся программистами на Python, не будут отвлекаться при чтении их, вы можете использовать те же файлы с некоторым другим языком, если это необходимо, и т. д.

+1

Да, я слишком много думал об этом, не был я. Вероятно, я это сделаю. Спасибо! – Jonathanb

3

Я бы рекомендовал использовать cookiecutter для генерации кода.

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