2009-11-12 5 views
2

J'ai une base de données qui contient le nom des fonctions Python et une chaîne pour leur code. Je veux que l'utilisateur puisse entrer un code Python et voir le résultat. Le problème est que j'ai besoin de connaître les noms des fonctions qu'ils appellent afin de récupérer le code de la base de données. Par exemple, si elles entrent cubic_fit(1, 2, get_data()), j'ai besoin d'un moyen d'obtenir les noms de fonctions cubic_fit et get_data. Y at-il un bon moyen de le faire?Obtenir les fonctions appelées dans une expression Python

+0

vous pourriez avoir besoin d'utiliser un décorateur afin d'attraper le nom de la fonction ... mais il pourrait y avoir un moyen plus facile que je ne sais pas. – jldupont

Répondre

11

La fonction intégrée compile fera pour vous exactement:

>>> compile("cubic_fit(1, 2, get_data())", '<string>', 'eval').co_names 
('cubic_fit', 'get_data') 

Et il est sûr de courir. Aucun code n'est en cours d'exécution juste compilé.

+0

@Nadia Alramli [En passant], Félicitations pour avoir passé la marque des représentants 10k en un temps record! Je trouve souvent vos réponses à ce point utiles et (et, malheureusement, vous me battez souvent dessus ;-)) Continuez votre bon travail! – mjv

+0

@mjv, merci! Vous êtes plus rapide que moi à coup sûr: 8,079 en 2 mois wow! :) –

2

Un exemple rapide pour vous a commencé. Notez que vous attendez une sémantique python valide pour que cela fonctionne.

Vous pouvez étendre à analyser aussi vos arguments ...

import token, tokenize, StringIO 

def extract_names(src): 
    rawstr = StringIO.StringIO(unicode(src)) 
    tokens = tokenize.generate_tokens(rawstr.readline) 
    for i, item in enumerate(tokens): 
     toktype, toktext, (srow,scol), (erow,ecol), line = item 
     if token.tok_name[toktype] == 'NAME': 
      print 'name:', toktext 

extract_names("cubic_fit(1, 2, get_data())") 

# --> output: 
# name: cubic_fit 
# name: get_data 
0

Si vous voulez juste les noms, les méthodes compile() et co_names fonctionneront mieux.

Vous pouvez également tirer parti de la capacité de eval() à utiliser n'importe quel objet de mappage en tant que paramètre local. Vous pouvez créer un objet de mappage pour rechercher et compiler les objets de votre base de données selon les besoins de eval().

Exemple:

class LookitUp(object): 
    def __init__(self): 
     # simulate some data 
     self.d = { "foo": "def foo(a):\n return a + 2"} 

    def __getitem__(self,key): 
     localdict = {} 
     c = compile(self.d.get(key,""),"<string>","exec") 
     eval(c,globals(),localdict) 
     return localdict[key] 

d = LookitUp() 

def bar(a): 
    return a - 1 

print "foo from database :",eval("foo(3)",globals(), d) 
print "bar from globals():",eval("bar(3)",globals(), d) 
print "foo(bar(3))  :",eval("foo(bar(3))",globals(), d) 

Résultat:

foo from database : 5 
bar from globals(): 2 
foo(bar(3))  : 4 

Vous devrez peut-être modifier en fonction de ce que votre source dans la base de données ressemble, mais il est un endroit pour commencer.

+0

C'est plus ou moins ce que je prévois de faire :) – exupero

Questions connexes