[Tutor] Re: Weird import problem with PythonIDE on Mac (was 'import problem')

Chris Smith smichr at bigfoot.com
Mon Apr 25 15:18:08 CEST 2005

On Friday, Apr 22, 2005, at 10:00 America/Chicago, Max Noel wrote:

>> Do you have a suggestion as to what can I give a module so it has 
>> enough information to execute a function that resides in __main__? 
>> Here is a visual of what is going on:
>> ------__main__
>> def y1():
>>   pass
>> import foo
>> foo.run(string_from_main) #what should I pass?
>> ------external module, foo
>> def run(string_from_main):
>> 	#
>> 	exec(string_from_main) #y1 is run as if it were in __main__
>> /c
> 	Python makes it easy to do because functions (and classes) are 
> objects. Here:
> # in __main__
> def y1():
>     pass
> import foo
> foo.run(y1)
> # in foo
> def run(functionFromMain):
>     functionFromMain()

Yes, I know about this, but this is not the problem.  The problem is 
knowing what *strings* to pass to the timeit module so it can access a 
function that is written in one's __main__. Basically, the timeit 
module uses a template to construct a function which is (in the timeit 
module) compiled and then executed.  You get to send two strings: an 
initialization string that is run once and the code string that appears 
in a loop.  Here, for example, is the function that is reconstructed 
and run without success (in mac's pythonIDE:

def inner(_it, _timer):
     from __main__ import y1  # I supplied this
     _t0 = _timer()
     for _i in _it:
         y1()                 # and I supplied this
     _t1 = _timer()
     return _t1 - _t0

The way the IDE works, this import fails.  There are two ways I have 
found around the problem:

1) wrap the functions of __main__ into a triple quoted string and then 
parsing it apart and sending it to timeit (not too elegant/pythonic):

### brute force passing of function to timeit

def y1():
	print 'y1 executed'
def y2():
	print 'y2 executed'

for f in funcs.split('def'):
     f = f.strip()
     if not f:
     name = f.split('(')[0]
     t=timeit.Timer('def '+f)
     print name,t.timeit(1)

2) the other approach is to add an additional argument to the timeit 
__init__ that accepts globals() from the calling program:

     def __init__(self, stmt="pass", setup="pass", timer=default_timer, 
glbls = globals):
         """Constructor.  See class doc string."""          # changed 
here - -^
         self.timer = timer
         stmt = reindent(stmt, 8)
         setup = reindent(setup, 4)
         src = template % {'stmt': stmt, 'setup': setup}
         self.src = src # Save for traceback display
         code = compile(src, dummy_src_name, "exec")
         ns = {}
         exec code in glbls, ns                              # and here
         self.inner = ns["inner"]

Then __main__ can send functions like this:

def y1():
	print 'y1 executed'
def y2():
	print 'y2 executed'
for f in [y1,y2]:
     func = f.__name__
     t=timeit.Timer(stmt = "%s()" % func, glbls = globals())
     print func, t.timeit(1)

{If you read to here, thanks.  Is there a better way to accomplish this 
with the current timeit module without modifying timeit?  i.e. is there 
another way to pass the needed information as a string that timeit's 
created function can execute?}


More information about the Tutor mailing list