热门标签:
Q:

Python生成Python

我有一组对象,我正在为其创建一个类,我想将每个对象存储为自己的文本文件。 我真的很想将它存储为Python类定义,它对我正在创建的主类进行子类化。 所以,我做了一些探查,发现了一个Python代码生成器effbot.org。我做了一些实验,这是我想出的:

#
# a Python code generator backend
#
# fredrik lundh, march 1998
#
# fredrik@pythonware.com
# 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')

这感觉真的很难看,有没有更清洁/更好/更pythonic的方式来做到这一点? 请注意,这不是我实际打算这样做的类,这是一个小类,我可以很容易地模拟在不太多的行。 此外,子类不需要在其中具有生成函数,如果我再次需要,我可以从超类调用代码生成器。

原网址
A:

我们使用Jinja2来填写一个模板。 这要简单得多。

模板看起来很像Python代码,其中有一些{{something}}替换。

所有回答

共 4 条

author avatar

这几乎是生成Python源代码代码的最佳方式。 但是,您也可以在运行时使用ast库生成Python可执行代码。 您可以使用抽象语法树构建代码,然后将其传递给compile()将其编译为可执行代码。 然后你可以使用eval()来运行代码。

我不确定是否有一种方便的方法来保存编译后的代码以供以后使用(即。 在.pyc文件中)。

author avatar

只需阅读您的评论wintermute-ie:

我拥有的是一堆行星 我想将每个存储为自己的文本 文件。 我不是特别依恋 将它们存储为python源代码, 但我很喜欢制作它们 人类可读。

如果是这样的话,那么看起来你不应该需要子类,而是应该能够使用相同的类并单独通过数据区分行星。 在这种情况下,为什么不把数据写入文件,当你需要程序中的行星对象时,读入数据来初始化对象呢?

如果你需要做一些像重写方法这样的事情,我可以看到写出代码-但是你不应该只是能够对所有行星都有相同的方法,只是使用不同的变量吗?

只写出数据的好处(它可以包括标签类型信息以提高可读性,当你读到它时会跳过)是非Python程序员在阅读它们时不会分心,如果需要,你可以使用其他语言

author avatar

我不确定这是否特别是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)

当然,这比你的例子要昂贵得多,我会警惕太多的元编程,但这是一个有趣的练习。 你可以扩展或使用这个,你认为合适;怎么样:

  • 添加write方法并将stdout重定向到this的对象以直接打印到脚本文件
  • 从它继承自定义输出
  • 添加属性getter和setter

如果你能听到任何你喜欢的消息,那就太好了。

author avatar

从我理解你正在尝试做的事情来看,我会考虑使用反射在运行时动态检查一个类,并根据它生成输出。 有一个很好的反思教程(A.K.a.内省)在http://diveintopython3.ep.io/.

您可以使用dir()函数来获取给定对象的属性的名称列表。 对象的doc字符串可通过__doc__属性访问。 也就是说,如果您想查看函数或类的doc字符串,可以执行以下操作:

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

相似问题