0

Why does eval() of expressions with list comprehension work fine, if done outside a function, but cease to work under all circumstances, as soon as I run the same commands inside a function? E. g., why does

fruit = ['apple', 'banana', 'cherry']
meat = ['chicken', 'beef', 'steak']
s = eval("[meat[k] for k, _ in enumerate(fruit)]")
print(s)

work, but not

def main():
    fruit = ['apple', 'banana', 'cherry']
    meat = ['chicken', 'beef', 'steak']
    s = eval("[meat[k] for k, _ in enumerate(fruit)]")
    print(s)
    return

main();

?

My example is a little contrived. But it's a minimal example nonetheless. In my actual applications I use more complicated expressions, but the above demonstrates the point at which eval() breaks down. I've also tried using eval(..., globals(), locals()), eval(..., None, locals()), etc., But nothing seems to help.

Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
Thomas
  • 175
  • 11
  • possible duplicate of https://stackoverflow.com/questions/25076883/creating-dynamically-named-variables-in-a-function-in-python-3-understanding-e – Bytes2048 Jun 18 '19 at 23:34
  • 1
    Try add `globals=locals()` to eval arguments – geckos Jun 18 '19 at 23:34
  • Try to this way: `def main(meat,fruit): s = eval('[meat[k] for k, _ in enumerate(fruit)]') print(s) return fruit = ['apple', 'banana', 'cherry'] meat = ['chicken', 'beef', 'steak'] if __name__ == '__main__': main(meat,fruit)` – arajshree Jun 18 '19 at 23:45
  • the problem is that `eval` is evaluating the expression as if it existed outside of a function, which means that the `meat` reference will be global, because the compiler cannot tag it as a free variable. just pass the `locals` as the globals, or better yet, **avoid using `eval` to begin with** – juanpa.arrivillaga Jun 18 '19 at 23:47
  • that linked duplicate isn't really a duplicate, although it is related – juanpa.arrivillaga Jun 18 '19 at 23:50
  • guys, it isn't a duplicate, I did read the other answers. @juanpa.arrivillaga The problem is, I really need to evaluate expressions, as I'm programming a kind if metacode. – Thomas Jun 19 '19 at 09:48
  • @arajshree the problem with this, is that I evaluate multiple expressions, the list of variables is not known in advance. – Thomas Jun 19 '19 at 09:48
  • 1
    @geckos tried `eval(..., globals=locals())`, but get `TypeError: eval() takes no keyword arguments`. Will try `eval(..., locals())` without the keyword. It worked!! – Thomas Jun 19 '19 at 09:48
  • @geckos Why is this necessary for list comprehension, but not for norm expressions? _E. g._ `eval("meat[2]")` works without needing the `locals()` argument. – Thomas Jun 19 '19 at 09:57
  • 1
    I don't really know for sure, but it may be something about the list comprehension having a distinct scope behavior, maybe some one can tell us :) – geckos Jun 19 '19 at 14:22
  • 1
    Yeap, generator expression has it own scope, this is why you need locals there, there is an answer here that has more information https://stackoverflow.com/questions/36616739/python-how-can-i-run-eval-in-the-local-scope-of-a-function – geckos Jun 19 '19 at 14:25
  • but why does it even sometimes work? – Thomas Jun 26 '19 at 11:19

0 Answers0