1

I have a manually maintained list of python functions and modules that will be used by a genetic algorithm and I want to be able to repeatedly call these and monitor the results.

test_exec.py

import os
from random import randint

def main():
    toolList = [{'file':'test1.py', 'function':'sum_even_numbers', 'args':['list'], 'return':['int']},
                {'file':'test1.py', 'function':'get_min_even_num', 'args':['list'], 'return':['int']}   ]
    for tool in toolList:
        for i in range(0,3):
            run(tool, [randint(10,99) for j in range(1,randint(2,5))])

def run(tool, args):
    mod = __import__( os.path.basename(tool['file']).split('.')[0])
    func = getattr(mod, tool['function'])
    tool['return'] = func(args)
    print('main called ' + tool['file'] + '->' + tool['function'] + ' with ', args, ' = ', tool['return'])

main()

test1.py

def sum_even_numbers(numbers):
    return sum([i for i in numbers if i % 2 == 0])

def get_min_even_num(numbers):
    return min([i for i in numbers if i % 2 == 0])

# other code in test1.py which we dont want to execute
print('test1.py has been run' )

results of the code:

test1.py has been run
('main called test1.py->sum_even_numbers with ', [30, 66, 25, 45], ' = ', 96)
('main called test1.py->sum_even_numbers with ', [92], ' = ', 92)
('main called test1.py->sum_even_numbers with ', [59, 73], ' = ', 0)
('main called test1.py->get_min_even_num with ', [59, 12, 61, 24], ' = ', 12)
('main called test1.py->get_min_even_num with ', [22], ' = ', 22)
('main called test1.py->get_min_even_num with ', [97, 94], ' = ', 94)

The code works, by calling a function in a module by string, but during the import this executes the entire file. Is there a better way to do this so that the entire module is not run?

acutesoftware
  • 1,091
  • 3
  • 14
  • 33

1 Answers1

5

When you import something from a module - even a standalone module-level function - the python interpreter has to parse/compile the whole file before giving you access to that function.

In the case of defs, this is harmless - they are just compiled into functions, no harm done. But sometimes you have "code that you don't want to be run", like your print in your example.

The canonical way of blocking code from being executed when you import a module is:

if __name__ == '__main__':
    # code that only gets executed when I explicitly run this module

More reading.

Community
  • 1
  • 1
roippi
  • 25,533
  • 4
  • 48
  • 73
  • 1
    And, to make it more concrete, in this case, it's likely that `# code that only gets executed ...` would be the call of `main` -- e.g. `main()` – mgilson Apr 30 '14 at 02:46
  • Ok, so if the entire file is always loaded and compiled I need to move my import command out of the loop, otherwise it will be importing the same modules multiple times – acutesoftware Apr 30 '14 at 03:26
  • 1
    re-importing a module is not a big deal. It only gets compiled once (the first time). Obviously for aesthetic reasons it's best to only import once, but the performance impact of importing multiple times is quite small. – roippi Apr 30 '14 at 03:37
  • Thanks for the responses. Yes, I confirmed there is minimal performance impact by doing 100,000 imports so I will resist the urge to do any premature optimization :) – acutesoftware Apr 30 '14 at 06:03