Using a dict as if it were a module namespace
BjornSteinarFjeldPettersen at gmail.com
Sun Jan 27 09:46:14 CET 2008
On Jan 27, 8:45 am, Steven D'Aprano <st... at REMOVE-THIS-
> I have a problem which I think could be solved by using a dict as a
> namespace, in a similar way that exec and eval do.
> When using the timeit module, it is very inconvenient to have to define
> functions as strings. A good alternative is to create the function as
> normal, and import it:
> def myfunc(x, y):
> return x+y
> timeit.Timer("myfunc(59, 60)", "from __main__ import myfunc").timeit()
> Not only is this an easy idiom to follow, but myfunc can live in another
> module: just replace __main__ with the module name.
> Now, I'm trying to build a suite of tests to use with timeit. I have a
> bunch of tests which I've created as dicts:
> test_suite= [dict(x=59, y=60), dict(x=-1, y=-2)]
> What I *think* I want to do is use the from ... import idiom to grab
> arguments from the dicts as if they were modules, but this doesn't work:
> expr = "myfunc(x, y)"
> for test in test_suite:
> setup = "from __main__ import myfunc; from test import x, y"
> t = timeit.Timer(expr, setup).timeit()
> Even if the Timer could see test, it is not a module and you can't import
> from it. Naturally.
> Alternatives that I have found:
> (1) Import the test and grab the values needed from it:
> setup = """from __main__ import myfunc, test
> x, y = test['x'], test['y']"""
> I don't like this one. It doesn't seem very elegant to me, and it gets
> unwieldy as the complexity increases. Every item I need from test has to
> be named twice, violating the principle Don't Repeat Yourself. If the
> tests change, the setup string has to be explicitly changed also.
> (2) Mess with the global namespace:
> setup = "from __main__ import myfunc"
> I don't like this one. It looks hackish, and I worry about conflicts and
> side-effects. If it works (and I haven't tested it) it relies on an
> implementation detail of timeit.Timer.__init__, namely the line
> "exec code in globals(), ns". Worst of all, it pollutes or even mangles
> the global namespace of the calling code, not the code being tested.
> (3) Explicitly pass a namespace dict to the Timer class, possibly even
> getting rid of setup altogether:
> test['myfunc'] = myfunc
> t = timeit.Timer(expr, '', ns=test).timeit()
> This would be the most elegant solution, but at this time it is
> completely hypothetical. Timer does not have that functionality.
> (4) Dump the test data straight into the setup string:
> setup = "from __main__ import myfunc; x = %(x)s; y = %(y)s" % t
> Again, unwieldy and against DRY. The additional disadvantage is that
> there are many types of test data that can't be converted to and from
> strings like that.
> What do others think? Have I missed something? What other alternatives
> are there?
You might have lost me, but wouldn't it be easier to do some variation
test_suite = [
'(x=59, y=60)', # either have strings here...
for test in test_suite:
# ... or convert the dicts to appropriate strings here...
expr = 'myfunc' + test
t = timeit.Timer(expr, 'from __main__ import myfunc').timeit()
More information about the Python-list