On Thu, 2012-06-21 at 21:25 +1000, John O'Hagan wrote: > Sometimes a function gets called repeatedly with the same expensive argument: > > def some_func(arg, i): > (do_something with arg and i) > > same_old_arg = big_calculation() > for i in lots_of_items: > some_func(same_old_arg, i) >
Another possibility is to refactor this into a callable class. class DoesSomethingWithExpensiveData(object): def __init__(self, arg): self.arg = arg def __call__(self, operand): return sum([self.arg, operand]) func = DoesSomethingWithExpensiveData(big_calculation()): for thing in a_bunch_of_things: print func(thing) Or you can write a function factory: def get_func(arg): def inner(operand): return sum([arg, operand]) return inner func = get_func(big_calculation()) for thing in a_bunch_of_things: print func(thing) > A simple case like that looks OK, but it can get messy when groups of > arguments > are passed between functions, especially if the arguments are used by > functions > called within the functions they are passed to (by other functions!). > > Maybe that's a code smell, but it can be cleaned up with: > > import functools > some_func = functools.partial(some_func, big_calculation()) > for i in lots_of_items: > some_func(i) > > But what about a generator? > > def some_func(): > arg = big_calculation() > while 1: > i = yield > (do_something with arg and i) > > some_gen = some_func() > some_gen.send(None) > for i in lots_of_items: > some_gen.send(i) > > I like this because it encapsulates the calculation of the arguments > inside the function that is using them without repeating it, and there are no > restrictions on argument order like partial. But sending None is annoying. :) > > Old news? Thoughts, criticisms, theories? > > -- > > John -- http://mail.python.org/mailman/listinfo/python-list