You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=<Date2014-08-23.03:25:00.464>created_at=<Date2008-04-01.12:13:46.612>labels= ['type-feature', 'library']
title='Pass a namespace to timeit'updated_at=<Date2014-08-23.15:28:53.867>user='https://bugs.python.org/peterotten'
I'd like to suggest a different approach than the one taken in rev.
54348 to improve timeit's scripting interface: allow passing it a
namespace. Reasons:
- It has smaller overhead for functions that take an argument:
>>> deff(a): pass
...
# trunk
>>> min(ht.Timer(lambdaf=f: f(42)).repeat())
0.54068493843078613
# my patch
>>> min(mt.Timer("f(42)", ns=dict(f=f)).repeat())
0.29009604454040527
it is more flexible. Example:
# working code, requires matplotlib
from timeit import Timer
from time import sleep
On the second thought, I actually wanted Timer to mimic eval without
realizing that eval uses positional rather than keywords arguments.
'locals' is obviously a bad choice for the keyword parameter because it
masks locals() builtin. Maybe 'local_namespace'?
Generally, when I use timeit from the interpreter prompt, I use "from
__main__ import *" as the setup code string. Then I can use all
currently defined global symbols directly :)
peterotten commented on Apr 2, 2008
peterottenmannequin
MannequinAuthor
More actions
Alexander, I'm fine with a more specific argument name. ns was what
the Timer already used internally.
Antoine, from __main__ import name1, ..., nameN works fine on the
command line, but inside a function you'd have to declare the names
you want to pass to the Timer as globals which I find a bit clumsy.
Apart from giving a syntax warning a star-import affects the generated
bytecode and produces the (slower) LOAD_NAME instead of LOAD_FAST.
Alexander, I'm fine with a more specific argument name. ns was what
the Timer already used internally.
Maybe it should be "locals" after all. It does not look like the
conflict with builtin locals() is an issue. Note that this is what
__import__ uses. I still recommend adding globals argument as well
for completeness and more accurate timings when timed code uses
globals.
lambertdw commented on Jan 24, 2009
lambertdwmannequin
Mannequin
More actions
This note is simply a reminder that Antoine's 'from __main__ import *'
solution fails in python3. Also, resolution of this issue probably
could incorporate bpo-1397474.
>>> import timeit
>>> timeit.timeit('None','from __main__ import *')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.0/timeit.py", line 227, in timeit
return Timer(stmt, setup, timer).timeit(number)
File "/usr/local/lib/python3.0/timeit.py", line 135, in __init__
code = compile(src, dummy_src_name, "exec")
File "<timeit-src>", line 2
SyntaxError: import * only allowed at module level
Would still be nice to have something like this. The timeit module API is still crippled, especially now that "from __main__ import *" doesn't work in a function anymore.
roippi commented on Aug 18, 2014
roippimannequin
Mannequin
More actions
Attached is a patch that adds a 'global' kwarg to the Timeit constructor, which does pretty much what it says on the tin: specifies a global namespace that exec() will use.
I originally had a 'locals' arg as well (to mirror the signature of eval/exec), but realized that the local vars I was passing to exec were not available to the inner function. Reason: the timeit module compiles/execs a *closure*, and closed-over variables and exec() simply do not play nicely. Possible workarounds were to munge locals() into the globals() dict, or to somehow inject the variables in the locals dict into the closure. I found neither of these options superior to simply not including a locals argument, for reasons of Least Surprise and maintainability.
Patch includes some basic tests and documentation. I am particularly uncomfortable with writing docs so those very likely need some polish.
roippi commented on Aug 18, 2014
roippimannequin
Mannequin
More actions
Correction, the name of the argument is 'globals', not 'global'.
Ah, good. The patch looks fine to me, except that you should add "versionchanged" tags in the documentation for the added parameter.
roippi commented on Aug 22, 2014
roippimannequin
Mannequin
More actions
Ah yes.
New patch improves the docs.
python-dev commented on Aug 23, 2014
python-devmannequin
Mannequin
More actions
New changeset e0f681f4ade3 by Antoine Pitrou in branch 'default':
Issue bpo-2527: Add a *globals* argument to timeit functions, in order to override the globals namespace in which the timed code is executed. http://hg.python.org/cpython/rev/e0f681f4ade3
Activity
peterotten commentedon Apr 1, 2008
I'd like to suggest a different approach than the one taken in rev.
54348 to improve timeit's scripting interface: allow passing it a
namespace. Reasons:
# working code, requires matplotlib
from timeit import Timer
from time import sleep
The above code works unaltered inside a function, unlike the hacks
using "from __main__ import ...".
The provided patch is against 2.5.1. If it has a chance of being
accepted I'm willing to jump through the necessary hoops:
documentation, tests, etc.
abalkin commentedon Apr 1, 2008
A more general approach would be to add both 'locals' and 'globals' to
be used by exec. At least, I would change 'ns' to 'locals'.
abalkin commentedon Apr 1, 2008
On the second thought, I actually wanted Timer to mimic eval without
realizing that eval uses positional rather than keywords arguments.
'locals' is obviously a bad choice for the keyword parameter because it
masks locals() builtin. Maybe 'local_namespace'?
pitrou commentedon Apr 1, 2008
Generally, when I use timeit from the interpreter prompt, I use "from
__main__ import *" as the setup code string. Then I can use all
currently defined global symbols directly :)
peterotten commentedon Apr 2, 2008
Alexander, I'm fine with a more specific argument name. ns was what
the Timer already used internally.
Antoine, from __main__ import name1, ..., nameN works fine on the
command line, but inside a function you'd have to declare the names
you want to pass to the Timer as globals which I find a bit clumsy.
Apart from giving a syntax warning a star-import affects the generated
bytecode and produces the (slower) LOAD_NAME instead of LOAD_FAST.
abalkin commentedon Apr 2, 2008
On Wed, Apr 2, 2008 at 2:42 AM, Peter Otten <report@bugs.python.org> wrote:
Maybe it should be "locals" after all. It does not look like the
conflict with builtin locals() is an issue. Note that this is what
__import__ uses. I still recommend adding globals argument as well
for completeness and more accurate timings when timed code uses
globals.
lambertdw commentedon Jan 24, 2009
This note is simply a reminder that Antoine's 'from __main__ import *'
solution fails in python3. Also, resolution of this issue probably
could incorporate bpo-1397474.
rhettinger commentedon Feb 5, 2009
Georg, why did you reassign this?
birkenfeld commentedon Feb 6, 2009
I'm sorry, this should have been another issue. Reassigning to you.
rhettinger commentedon Apr 7, 2009
See related discussion in bpo-5441 and bpo-1397474.
pitrou commentedon Aug 6, 2014
Would still be nice to have something like this. The timeit module API is still crippled, especially now that "from __main__ import *" doesn't work in a function anymore.
roippi commentedon Aug 18, 2014
Attached is a patch that adds a 'global' kwarg to the Timeit constructor, which does pretty much what it says on the tin: specifies a global namespace that exec() will use.
I originally had a 'locals' arg as well (to mirror the signature of eval/exec), but realized that the local vars I was passing to exec were not available to the inner function. Reason: the timeit module compiles/execs a *closure*, and closed-over variables and exec() simply do not play nicely. Possible workarounds were to munge locals() into the globals() dict, or to somehow inject the variables in the locals dict into the closure. I found neither of these options superior to simply not including a locals argument, for reasons of Least Surprise and maintainability.
Patch includes some basic tests and documentation. I am particularly uncomfortable with writing docs so those very likely need some polish.
roippi commentedon Aug 18, 2014
Correction, the name of the argument is 'globals', not 'global'.
pitrou commentedon Aug 21, 2014
Ben, thanks for the patch. Have you signed a contributor's agreement? You can find it at https://www.python.org/psf/contrib/contrib-form/
roippi commentedon Aug 22, 2014
I did sign one right after I submitted the patch. Takes a few days for the asterisks to propagate I guess :)
pitrou commentedon Aug 22, 2014
Ah, good. The patch looks fine to me, except that you should add "versionchanged" tags in the documentation for the added parameter.
roippi commentedon Aug 22, 2014
Ah yes.
New patch improves the docs.
python-dev commentedon Aug 23, 2014
New changeset e0f681f4ade3 by Antoine Pitrou in branch 'default':
Issue bpo-2527: Add a *globals* argument to timeit functions, in order to override the globals namespace in which the timed code is executed.
http://hg.python.org/cpython/rev/e0f681f4ade3
pitrou commentedon Aug 23, 2014
Thank you, Ben! Your patch is now pushed to the default branch.
roippi commentedon Aug 23, 2014
Thanks Antoine. Cheers :-)