2017-08-20 2 views
1

exec() de l'intérieur d'une fonction donne une sortie différente, même si je passe tous les paramètres nécessaires à cette fonction. Considérez ce code:exec() avec boucle imbriquée dans la compréhension de la liste à l'intérieur de l'erreur de fonction

def list_filter(expr,datalist,includelist) : 
    exec(expr) 
    print outlist 


datalist=['try to kill me','black image'] 
includelist=['me'] 
expr="outlist = [i for i in datalist if all(j in i for j in includelist) ]" 
exec(expr) 
print outlist 
list_filter(expr,datalist,includelist) 

J'ai vérifié le cas similaire ici: How does exec work with locals?

Mais ceci est une autre erreur, où j'utilise la version 2.7.13 et je vérifie sous l'état général, le exec() normalement n'a pas d'erreur du tout. J'ai trouvé ce problème apparaît quand il y a une «boucle imbriquée» dans l'énoncé de compréhension de la liste, comme en utilisant all() ou any(). Comme dans ce cas, si je supprime le if condition de la liste de compréhension (faites-le pour être expr = "outlist = [i for i in datalist ]") alors je vais obtenir la bonne sortie comme d'habitude.

Une idée pourquoi?

+2

Quel est le problème global que vous essayez de résoudre? Je doute que exec soit la bonne voie. –

+0

Il se passe quelque chose de bizarre ici parce que l'expression génératrice à l'intérieur du 'all (...)' est compilée en interne dans une sorte d'appel de fonction, et cela semble causer des problèmes en combinaison avec 'exec'. Cela fonctionne comme prévu si vous utilisez une liste de compréhension à la place: 'all ([j dans i pour j dans includelist])'. Cela dit, vous ne devriez probablement pas utiliser 'exec'. –

+0

@AlexHall: je veux modifier dans l'expr par exemple: ** expr = "outlist = [i__strip____case__ pour i dans la liste]" **. donc je peux utiliser ** expr = expr.replace ('__ strip __', '. lstrip(). rstrip()' si stripmode else '') ** ou ** expr = expr.replace ('__ cas __', '.() «sinon casse autrement») **. Ces deux seuls exemples d'altération (strip() et lower()), dans le cas réel, il y aura un paramètre de style de matrice se produire. Plutôt que d'utiliser une structure normale si -then, je veux juste essayer de faire en utilisant la méthode de remplacement de chaîne. De cette façon, je peux facilement modifier l'expression en tant que chaîne. – andio

Répondre

0

Presque toujours c'est une mauvaise idée d'utiliser exec dans ce cas, vous ne devriez probablement pas l'utiliser du tout.

Mais puisque vous avez demandé: Il fonctionne correctement si vous passez dans les variables du champ d'application locale:

def list_filter(expr, datalist, includelist): 
    exec(expr, locals()) 
    print outlist 

Je ne suis pas très familier avec les règles de portée pour exec mais je trouvais souvent que vous devez transmettre les variables explicitement (en particulier si le exec n'est pas dans la portée globale).

Dans votre cas, vous pouvez même les passer explicitement:

def list_filter(expr, datalist, includelist): 
    exec(expr, {'datalist': datalist, 'includelist': includelist}) 
    print outlist 

Il est même indiqué dans le documentation que vous devrez peut-être passer les variables du champ d'application à exec:

Le construit -dans les fonctions globals() et locals() renvoyer le dictionnaire global et local actuel, respectivement, ce qui peut être utile à transmettre pour utilisation par exec.