Slowness in compile()/eval()
Alex Martelli
aleax at aleax.it
Thu Jan 17 11:56:37 EST 2002
"Pedro Rodriguez" <pedro_rodriguez at club-internet.fr> wrote in message
news:pan.2002.01.17.17.35.37.25082.4228 at club-internet.fr...
...
> > Right. Local is faster than global, exactly because it can be loaded
> > without a lookup (LOAD_NAME).
>
> Sorry, but there is no global variable named 'i'. Does LOAD_NAME do a
> standard look up in namespaces, while LOAD_FAST is used when the compiler
> know that a local lookup will be sufficient ?
Yes. If you use an exec statement inside a function, then the
compiler knows it doesn't know any more whether something is to
be looked up locally or globally, so it has to use LOAD_NAME
throughout the function, and that does make things a lot worse.
> If this is so, this means that 'compile()' takes the worst, or better
> said the more 'general', guess on how to compile it, by not assuming
> that variables in expression may be in local scope.
Sure, just as the compiler has to do if it sees an exec statement
anywhere inside a function's scope.
> > Change your function to:
> > def f(): return i+i
> > and the time difference should just about go away.
>
> No, because I don't know what expression I have to compute. I am trying
I'm talking about the difference with the function you had coded
just like this but with i as an argument: it WILL be similarly slow.
I do understand you want to compile code dynamically. What I'm saying
is, the non-fast-local lookup will be slower in any case.
> - if this is the case, could this an idiom :
> instead of writing :
> code = compile("some expr", '<string>', "eval")
> val = eval(code)
>
> one should consider writing :
> code = compile("def __f(v1,v2,...):\n return some_expr\n"
> , '<string>', 'exec')
> eval(code)
You must use exec code here, not eval(code).
> f = locals()["__f"]
> val = f(v1, v2, ...)
You can then choose to access __f(v1, v2) directly. But given
the exec, which turns off fast-lookup, it will be slow anyway.
> - the proposed idiom above looks dirty to me (locals trick), there
Unnecessary, when using the exec statement.
> may be a better way through the 'new' module, but I don't have found
> it yet.
There's almost invariably a better way than using exec, yes, for
just about any task. You may need "bytecode hacks" to let you
produce the codeobject you want, though.
> - where do the definition of 'f' goes in :
>
> # ---------------------------------------------------------------------
> m.py
> # ---------------------------------------------------------------------
> def a():
> code = compile("def f():\n pass\n", '<string>', "exec")
> eval(code)
eval should reject code, since it was compiled for exec, not for
eval (it's a statement, not an expression). You should open a
bug report about this, I believe, since this is the bug (in
eval) which produces the following anomaly:
> print locals().keys()
> print locals()["f"]
> print f
Since no exec has been used (just eval), the compiler "knows"
the f name used in the last statement cannot be local and
only looks for it globally (and doesn't find it).
> - why is eval("some_expr") so slow with Python 2.x (will profile it)
Profiling is a good idea, but I think you won't find it slower
(once the compile step is removed, of course -- recompiling each
and every time WILL slow things down) than the same expression
in a normal setting, when both (e.g.) access data globally.
Alex
More information about the Python-list
mailing list