Ce n'est pas un problème d'écrire un convertisseur Je vais écrire un petit contenu d'essai. Pour rappel, je touche rarement avec Python.
Par exemple, je souhaite générer une fonction qui double l'argument v et le renvoie lorsque la chaîne de caractères «" v * 2 "» est donnée. (On sait que le nom de l'argument est v)
Comme dans l'exemple ci-dessus, si la chaîne donnée est une instruction unique, c'est très simple, utilisez simplement une opération de chaîne pour en faire un lambda et l'évaluez.
single.py
text = "v * 2"
func = eval("lambda v:" + text)
La méthode ci-dessus ne peut pas être utilisée si la chaîne donnée peut contenir plusieurs expressions. Par exemple
from System.Windows import Thickness
Thickness(v, 0, 0, 0)
Considérez le cas où est spécifié. Pour le moment, la seule chose qui me vient à l'esprit est d'utiliser une opération de chaîne pour créer une fonction def, puis de l'exécuter. (Ce code ne renvoie None que pour la fonction générée, mais j'en parlerai plus tard)
multi.py
text = """
from System.Windows import Thickness
Thickness(v, 0, 0, 0)
"""
import re
source = "def test(v):\n" + re.sub("^", " ", text, flags=re.M)
exec(source)
return test
C'est très bien dans la plupart des cas, mais par exemple, lorsqu'un littéral multiligne est donné, il y a un problème que le contenu du littéral est indenté par le traitement de retrait simple par l'expression régulière ci-dessus. ..
"""value of v is:
{v}""".format(v=v)
C'est un cas rare que vous n'avez pas vraiment besoin de considérer, mais c'est un peu inconfortable de savoir qu'il y a un mauvais modèle, donc comme alternative, nous en ferons une fonction par conversion ast.
def test (v): pass
.La procédure.
Cela ressemble à ceci lorsqu'il est écrit dans le code.
functionize.py
import ast
class _MakeFunction(ast.NodeTransformer):
def __init__(self, body):
self.body = body
def run(self):
template_ast = ast.parse('def test(v): pass', mode='exec')
return self.visit(template_ast)
def visit_Pass(self, node):
return ast.parse(self.body, mode='exec').body
if __name__ == '__main__':
body = "from System.Windows import Thickness\nThickness(v, 0, 0, 0)"
functionized_ast = _MakeFunction(body).run()
exec(compile(functionized_ast, '<string>', mode='exec'))
Maintenant, c'est une fonction, mais comme je l'ai écrit plus tôt, il n'y a pas de valeur de retour en l'état. Donc, à l'aide de la conversion ast, réécrivez-la pour que le résultat de la dernière expression évaluée soit renvoyé comme valeur de retour comme Ruby. La procédure est la suivante.
_retval_ = None
au début de la fonctionreturn _retval_
à la fin de la fonction_retval_
.Écrivons un Transformer qui fait cela dans le code.
functionize.py
class _ReturnLastResult(ast.NodeTransformer):
def visit_FunctionDef(self, node):
self.generic_visit(node)
retval_assign = \
ast.Assign(targets=[ast.Name(id='_retval_', ctx=ast.Store())],
value=ast.NameConstant(value=None))
retval_return = \
ast.Return(value=ast.Name(id='_retval_', ctx=ast.Load()))
node.body.insert(0, retval_assign)
node.body.append(retval_return)
return ast.fix_missing_locations(node)
def visit_Expr(self, node):
target = ast.Name(id='_retval_', ctx=ast.Store())
assign = ast.copy_location(
ast.Assign(targets=[target], value=node.value), node)
return assign
Le code final ressemble à ceci. https://gist.github.com/wonderful-panda/8a22b74248a60cc8bb22
Après tout, j'ai décidé de ne considérer que la déclaration unique dans l'entrée d'origine et je ne l'ai pas utilisée.
Recommended Posts