Comment voulez-vous faire un python 'eval' que dans un contexte de l'objet?
Est-il possible de faire quelque chose comme
c = MyObj()
c.eval("func1(42)+func2(24)")
en Python..c'est à dire func1() et func2() est évaluée dans le champ d'application de l'objet 'c' (si ils ont des fonctions de membre au sein de cette définition de la classe)? Je ne peux pas faire une analyse simple, depuis que mon application de l'eval chaînes peut devenir arbitrairement complexe. Je pense faire de la magie avec l'ast module pourrait faire l'affaire, mais en raison de la très peu de littérature sur les ast, je ne sais pas où chercher:
import ast
class MyTransformer(ast.NodeTransformer):
def visit_Name(self, node):
# do a generic_visit so that child nodes are processed
ast.NodeVisitor.generic_visit(self, node)
return ast.copy_location(
# do something magical with names that are functions, so that they become
# method calls to a Formula object
newnode,
node
)
class Formula(object):
def LEFT(self, s, n):
return s[:n]
def RIGHT(self, s, n):
return s[0-n:]
def CONCAT(self, *args, **kwargs):
return ''.join([arg for arg in args])
def main():
evalString = "CONCAT(LEFT('Hello', 2), RIGHT('World', 3))"
# we want to emulate something like Formula().eval(evalString)
node = ast.parse(evalString, mode='eval')
MyTransformer().visit(node)
ast.fix_missing_locations(node)
print eval(compile(node, '<string>', mode='eval'))
Vous pourriez avoir plus de chance juste de créer votre propre langage simple et d'analyser cela avec quelque chose comme pyPEG
Pouvez-vous vous limiter uniquement à des méthodes sur l'objet, ou voulez-vous être en mesure d'appeler d'autres choses comme des variables globales ou de nommer explicitement les autres classes?
eval() peut prendre "globals" et "habitants" des dictionnaires en tant que paramètres. Peut-être que vous pouvez remplir ces avec vos fonctions et de les transmettre?
Honnêtement, je pense que vous doit être explicitement l'analyse ici. Il n'est pas trivial, mais c'est parce que ce que vous essayez de réaliser n'est pas trivial. Si cela ne fonctionne pas, @LAK suggestion de remplissage d'un explicite le dictionnaire à utiliser en tant que contexte est probablement encore plus simple que de faire semblant avec un objet. Mais si vous vous voulez utiliser des objets comme les contextes, voir ma réponse.
Aussi, si "l'eval chaînes peut devenir arbitrairement complexe"—sont-ils arbitrairement complexe Python? Quelqu'un peut-eval, disons,
Pouvez-vous vous limiter uniquement à des méthodes sur l'objet, ou voulez-vous être en mesure d'appeler d'autres choses comme des variables globales ou de nommer explicitement les autres classes?
eval() peut prendre "globals" et "habitants" des dictionnaires en tant que paramètres. Peut-être que vous pouvez remplir ces avec vos fonctions et de les transmettre?
Honnêtement, je pense que vous doit être explicitement l'analyse ici. Il n'est pas trivial, mais c'est parce que ce que vous essayez de réaliser n'est pas trivial. Si cela ne fonctionne pas, @LAK suggestion de remplissage d'un explicite le dictionnaire à utiliser en tant que contexte est probablement encore plus simple que de faire semblant avec un objet. Mais si vous vous voulez utiliser des objets comme les contextes, voir ma réponse.
Aussi, si "l'eval chaînes peut devenir arbitrairement complexe"—sont-ils arbitrairement complexe Python? Quelqu'un peut-eval, disons,
'func1(42) + func2(24) + os.system("rm -rf /")'
?
OriginalL'auteur Vineet Bansal | 2012-12-17
Vous devez vous connecter pour publier un commentaire.
Vous avez presque certainement ne voulez pas le faire, mais vous peut.
Le contexte de
eval
est les variables globales et locales des dictionnaires que vous voulez évaluer votre code. Les cas les plus courants sont probablementeval(expr, globals(), mycontext)
eteval(expr, mycontext)
, remplacez la valeur par défaut des contextes locaux et mondiaux, respectivement, en laissant l'autre seul. En remplaçant le contexte local d'un objet dictionnaire est similaire à l'exécution de "l'intérieur" (méthode de) cet objet—bien garder à l'esprit que d'être un membre de la fonction" ne pas faire autant de bien que vous pourriez vous attendre si vous n'avez pas deself
pour appeler d'autres fonctions membre sur...De toute façon, voici un exemple rapide:
Gardez à l'esprit que
__dict__
peut ne pas être exactement ce que vous voulez ici. Par exemple:Pour faire ce travail de la manière que vous voulez, vous devez savoir exactement comment définissez vous le souhaitez, en Python termes—qui nécessite de connaître un peu plus sur la manière dont les objets travaille sous les couvertures (MRO, peut-être descripteurs, etc.).
Si vous avez vraiment besoin
eval
, et vous avez vraiment besoin pour fournir de l'arbitraire des contextes, vous êtes probablement mieux de construction de ces explicitement les contextes (comme les dictionnaires) plutôt que d'essayer de forcer les objets dans ce rôle:Cette utilisation est beaucoup plus proche du style Javascript que vous essayez d'imiter en Python de toute façon.
Bien sûr, à la différence de JS, Python ne permet pas de mettre de multiples définitions de ligne à l'intérieur d'une expression, donc, pour les cas complexes que vous avez à faire cela:
Mais sans doute que c'est presque toujours plus lisible (qui est en fait l'argument derrière Python ne permettant pas de multi-définitions de ligne dans des expressions).
OriginalL'auteur abarnert
Donc, je vous conseille de faire quelque chose comme ceci:
Semble que vous avez besoin. Permettez-moi de vous expliquer comment cela fonctionne.
eval
accepte les habitants et globals en tant que paramètres.globals
dictionnaire de tous les "précieux" délimitée méthodes.S
définition de la classe. Comment obtenir tous les "précieux" méthodes? Simplefilter
noms deS.__dict__
afin de vérifier si le nom de la méthode commence à partir de__
ou pas (vous voyez, à ce que le résultat nous obtenons liste avec les 1 point -add
fonction).target
= instance deS
classe qui sera "eval contexte".__dict__
magasins de fonctions, chaque fonction est non-descripteur de données et délimitée méthode peut être récupérée simplement avecfunc.__get__(obj, type(obj))
. Cette opération est réalisée dansmap
.dict
.globals
àeval
fonction.Je l'espère, cela aidera.
OriginalL'auteur Alexey Kachayev
La solution proposée ci-dessus pour remplir
locals
fonctionne bien dans la plupart des cas, mais peut être problématique dans le cas de propriétés (données de descripteurs). Celles-ci sont évaluées une fois lorsque le dictionnaire est rempli. Cela signifie que plusieurs références pour le même nom de variable retournera toujours exactement la même instance, qui peut ne pas être le comportement attendu dans le cas de propriétés.Ce problème peut être résolu en notant que
eval
s'attend à unlocals
argument que se comporte comme undict
(par opposition aux variables globales, qui doit être undict
). En d'autres termes, nous pouvons remplacer__getitem__
dans votre instance pour résoudre les noms de variables à la volée dans le cadre de l'instance et de passer directement commelocals
attributeval
. Votre exemple peut donc être mis en œuvre comme:Cette astuce devrait travailler avec l'héritage, les méthodes statiques, les méthodes de la classe et de propriétés. Enfin, à l'aide de
dir
etgetattr
évite le besoin d'interagir directement avec__dict__
ou__mro__
, bien que les résultats dedir
peut pas toujours complet.OriginalL'auteur nrtc
Vous pourriez avoir un coup d'oeil à la accepté de répondre à cette question: "Le bloc de commandes qui doivent être exécutées dans le avec-déclaration".
Cela a été un bon moyen pour moi de créer ma propre contextes dans lesquels des opérations mathématiques sur des tableaux rectangulaires, tels que Python Pandas trames de données, "fonctionne" sans avoir besoin de s'embêter avec le laid supplémentaire Pandas de la syntaxe. Par exemple, quand j'écris "
a = x*y
" à l'intérieur du contexte, il assigne automatiquementa
comme un attribut de l'objet de contexte, et il sait à effectuer vectoriel des opérations avec le contexte de l'objetx
ety
attributs.J'ai trouvé ce contexte, des trucs à être très très utile, malgré le fait que chaque fois que je demande sur StackOverflow, je reçois souvent des trollish réponses qu'il ne doit pas être ce que je veux vraiment faire.
Vous pourriez probablement obtenir que cela fonctionne pour le contexte dans lequel
eval
semble que pour les fonctions de trop.OriginalL'auteur ely