2009-09-01 16 views
10

Tengo un grupo de objetos para el que estoy creando una clase para la que quiero almacenar cada objeto como su propio archivo de texto. Realmente me gustaría almacenarlo como una definición de clase de Python que subclasifica la clase principal que estoy creando. Entonces, investigué un poco y encontré un Generador de código Python en effbot.org. Hice un poco de experimentar con ella y esto es lo que ocurrió:Python que genera 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') 

que se siente muy feo, ¿hay un/una mejor manera más limpia/más Pythonic para hacer esto? Tenga en cuenta que esta no es la clase con la que realmente intento hacer esto, esta es una clase pequeña que puedo simular fácilmente en no demasiadas líneas. Además, las subclases no necesitan tener la función de generación en ellas, si lo necesito de nuevo, puedo simplemente llamar al generador de códigos desde la superclase.

+0

No use pestañas para sangrar Python, use espacios :) –

+0

Sí, establece eso como el valor predeterminado, pero sobreescribí esa variable con 4 espacios. – Jonathanb

Respuesta

22

Usamos Jinja2 para completar una plantilla. Es mucho más simple.

La plantilla se parece mucho al código de Python con unos pocos reemplazos {{something}} en él.

+0

Por mi comentario a Anon, voy a utilizar un sistema de plantillas. Voy a mirar de cerca a Jinja, ¡gracias por la propina! – Jonathanb

+2

hay un ejemplo de esto? – KJW

+0

¡Esta es una excelente manera de hacerlo! – specialscope

5

Esta es la mejor forma de generar Python fuente código. Sin embargo, también puede generar código ejecutable de Python en tiempo de ejecución utilizando la biblioteca ast. (Me vinculé a la versión de Python 3 porque es más capaz que la versión 2.x). Puede construir código usando el árbol de sintaxis abstracta, luego pasarlo a compile() para compilarlo en código ejecutable. Luego puede usar eval para ejecutar el código.

No estoy seguro de si hay una manera conveniente de guardar el código compilado para usarlo más tarde (es decir, en un archivo .pyc).

+0

bueno, realmente quiero algo legible para los humanos. código ejecutable tiende a no ser. – Jonathanb

+0

Bastante, voy a dejar esta respuesta aquí en caso de que sea útil para alguien más con una pregunta similar. –

0

Por lo que entiendo que estás tratando de hacer, consideraría usar la reflexión para examinar dinámicamente una clase en tiempo de ejecución y generar resultados basados ​​en eso. Hay un buen tutorial sobre reflexión (A.K.A. introspection) al http://diveintopython3.ep.io/.

Puede usar la función dir() para obtener una lista de nombres de los atributos de un objeto dado. La cadena de documentación de un objeto es accesible a través del atributo __doc__. Es decir, si desea buscar en la cadena de documentación de una función o clase que usted puede hacer lo siguiente:

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

Lo que tengo es un grupo de planetas que quiero almacenar cada uno como sus propios archivos de texto. No estoy particularmente apegado a almacenarlos como código fuente de Python, pero estoy apegado a que sean legibles por humanos. – Jonathanb

1

no estoy seguro de si esto es especialmente Pythonic, pero se puede usar la sobrecarga de operadores:

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) 

Esto es, por supuesto, mucho más costoso de implementar que su ejemplo, y yo sería cauteloso con demasiada meta-programación, pero fue un ejercicio divertido.Puede extender o usar esto como mejor le parezca; ¿qué tal:

  • la adición de un método de escritura y redirigir la salida estándar a un objeto de este imprimir directamente a un archivo de script
  • heredar de ella para personalizar la salida
  • añadir captadores de atributos y definidores

Sería genial escuchar sobre lo que sea que vayas :)

7

Acaba de leer tu comentario a wintermute - es decir:

Lo que tengo es un grupo de planetas que Quiero almacenar cada uno como sus propios archivos de texto . No estoy especialmente conectado para almacenarlos como código fuente de Python, pero estoy vinculado a hacerlos legibles por el ser humano .

Si ese es el caso, parece que no debería necesitar subclases pero debería ser capaz de utilizar la misma clase y distinguir los planetas a través de datos solamente. Y en ese caso, ¿por qué no simplemente escribir los datos en archivos y, cuando necesita los objetos planetarios en su programa, leer los datos para inicializar los objetos?

Si necesita hacer cosas como métodos de sobreescritura, podría ver escribir código, pero ¿no debería simplemente ser capaz de tener los mismos métodos para todos los planetas, simplemente usando variables diferentes?

La ventaja de simplemente escribir los datos (puede incluir información de tipo de etiqueta para legibilidad que omitirías cuando la lees) es que los programadores que no son Python no se distraerán al leerlos, podrías usar los mismos archivos con algún otro idioma si es necesario, etc.

+1

Sí, estaba pensando demasiado acerca de esto, no era yo. Eso es lo que haré. ¡Gracias! – Jonathanb

Cuestiones relacionadas