Ответ 1
Мы используем Jinja2 для заполнения шаблона. Это намного проще.
Шаблон очень похож на код Python с несколькими заменами {{something}}
.
У меня есть группа объектов, для которых я создаю класс, для которого я хочу сохранить каждый объект в виде собственного текстового файла. Я действительно хотел бы сохранить его как определение класса Python, которое подклассифицирует основной класс, который я создаю. Итак, я немного пошутил и нашел генератор кода Python на effbot.org. Я немного экспериментировал с этим, и вот что я придумал:
#
# 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')
Это кажется действительно уродливым, есть ли более чистый/лучший/более питонический способ сделать это? Обратите внимание, что это не тот класс, на котором я действительно намереваюсь это сделать, это небольшой класс, который я могу легко объединить в не слишком много строк. Кроме того, подклассам не требуется иметь в них функцию генерации, если мне это нужно снова, я могу просто вызвать генератор кода из суперкласса.
Мы используем Jinja2 для заполнения шаблона. Это намного проще.
Шаблон очень похож на код Python с несколькими заменами {{something}}
.
Просто прочитайте свой комментарий к wintermute - ie:
У меня есть куча планет, которые Я хочу хранить каждый как свой собственный текст файлы. Я не особенно привязан для их хранения в качестве исходного кода на основе python, но я привязан к их созданию читаемый человек.
Если это так, то кажется, что вам не нужны подклассы, но они должны иметь возможность использовать один и тот же класс и отличать планеты только от данных. И в этом случае, почему бы просто не записывать данные в файлы и, когда вам нужны объекты планеты в вашей программе, читать данные для инициализации объектов?
Если вам нужно было сделать что-то вроде переопределяющих методов, я мог бы видеть, как писать код, но разве вы не должны иметь одни и те же методы для всех планет, просто используя разные переменные?
Преимущество просто выписывания данных (это может включать информацию типа ярлыка для читаемости, которую вы пропустили, когда вы ее прочитали) заключается в том, что программисты, не использующие Python, не будут отвлекаться при чтении их, вы можете использовать при необходимости, файлы с другим языком.
Это в значительной степени лучший способ генерации исходного кода Python. Однако вы также можете генерировать исполняемый код Python во время выполнения, используя библиотеку ast
. (Я ссылался на версию Python 3, потому что она более способна, чем версия 2.x.) Вы можете создать код, используя абстрактное синтаксическое дерево, а затем передать его в compile()
чтобы скомпилировать его в исполняемый код. Затем вы можете использовать eval
для запуска кода.
Я не уверен, есть ли удобный способ сохранить скомпилированный код для последующего использования (т. .pyc
файле .pyc
).
Я бы рекомендовал использовать cookiecutter для генерации кода.
Я не уверен, что это особенно 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)
Это, конечно, намного дороже, чем ваш пример, и я бы опасался слишком большого метапрограммирования, но это было весело. Вы можете расширять или использовать это, как вы сочтете нужным; как насчет:
Было бы здорово услышать о том, с чем вы столкнулись:)
Из того, что, как я понимаю, вы пытаетесь сделать, я бы подумал об использовании рефлексии для динамического изучения класса во время выполнения и генерации вывода на основе этого. Существует хороший учебник по отражению (интроспекция А.К.А.) на http://diveintopython3.ep.io/.
Вы можете использовать функцию dir()
, чтобы получить список имен атрибутов данного объекта. Строка doc объекта доступна через атрибут __doc__
. То есть, если вы хотите посмотреть на строку документа функции или класса, вы можете сделать следующее:
>>> def foo():
... """A doc string comment."""
... pass
...
>>> print foo.__doc__
A doc string comment.
У меня был очень хороший опыт работы с Red Baron при создании кода.
Он прост в использовании и очень прост в реализации.