I'm trying to make life as easy as possible for my users while providing them with complete flexibility. I need to write functions for them to use, but the trick is that a user needs to pick the function before running it. Here's what I would like to do:
def standardGenerator(obj,param=8.0):
# algorithm which generates stuff based on obj and param
return stuff
opts.usersChoice = standardGenerator
in this example, opts
is an option container which is provided to the user to set whatever options they want. When they're done setting all their options, they pass opts
back to me.
now the issue is that obj
will not be known until after opts
is in my hands, but maybe a user wants params=4.0
instead of my default. My question is what is the easiest way to allow a user to set param
?
here are the ideas I thought of:
def standardGenerator4(obj):
return standardGenerator(obj,param=4.0)
opts.usersChoice = standardGenerator4
opts.usersChoice = lambda obj: standardGenerator(obj,4.0)
probably lambda is the best idea, but i'm wondering if there's some other way to do this without requiring users to know what a lambda function is...
Well, another way to do this is to use functools.partial
.
Why not make it a class with __call__
?
class standardGenerator(object):
def __init__(self, param=8.0):
self.param = param
def __call__(self, obj):
# do stuff with obj and self.param
The users code does this:
opts.usersChoice = standardGenerator() # for default, or...
opts.usersChoice = standardGenerator(4.0)
Then opts.usersChoice
is callable just like before, with only one argument for obj
.
EDIT: If you have several functions and don't want to convert them all to classes, you could make a wrapper class:
class wrapper(object):
def __init__(self, func, **args):
self.func, self.args = func, args
def __call__(self, *args):
return self.func(*args, **self.kwargs)
Then your old function could be used "raw" the same as before, or like this for a user-defined argument:
opts.usersChoice = wrapper(standardGenerator, param=4.0)
I think the first solution is cleaner, and the second solution is probably starting to duplicate functools.partial
, but you get the idea.
EDIT: Another thing you could do, which is arguably evil, is use operator overloading:
class _standardGenerator(object):
def __init__(self, param = 8.0):
self.param = param
# overload << to make it look most evil
def __lshift__(self, other):
return _standardGenerator(other)
def __call__(self, obj):
# do stuff with self.param and obj
standardGenerator = _standardGenerator()
# user code for default
opts.usersChoice = standardGenerator
# user code for nondefault
opts.usersChoice = standardGenerator << 4.0
Of course, I think it's infinitely cleaner to use a regular class and have the user instantiate it him/herself, but if you really don't like those parentheses on the end of standardGenerator
something like this would do the trick.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With