Python 如何在不运行函数的情况下为函数部分设置参数?

Python 如何在不运行函数的情况下为函数部分设置参数?,python,function,Python,Function,我试图让我的用户的生活尽可能简单,同时为他们提供完全的灵活性。我需要编写函数供他们使用,但诀窍是用户需要在运行函数之前选择函数。以下是我想做的: def standardGenerator(obj,param=8.0): # algorithm which generates stuff based on obj and param return stuff opts.usersChoice = standardGenerator 在本例中,opts是一个选项容器,提供给用户设置

我试图让我的用户的生活尽可能简单,同时为他们提供完全的灵活性。我需要编写函数供他们使用,但诀窍是用户需要在运行函数之前选择函数。以下是我想做的:

def standardGenerator(obj,param=8.0):
   # algorithm which generates stuff based on obj and param
   return stuff

opts.usersChoice = standardGenerator
在本例中,
opts
是一个选项容器,提供给用户设置他们想要的任何选项。设置完所有选项后,他们会将
opts
返回给我

现在的问题是,
obj
直到
opts
在我手中之后才会被知道,但可能用户想要
params=4.0
而不是我的默认值。我的问题是,允许用户设置
param
的最简单方法是什么

以下是我想到的想法:

def standardGenerator4(obj):
   return standardGenerator(obj,param=4.0)
opts.usersChoice = standardGenerator4

opts.usersChoice = lambda obj: standardGenerator(obj,4.0)

也许lambda是最好的主意,但我想知道是否有其他方法可以做到这一点,而不需要用户知道lambda函数是什么…

好吧,另一种方法是使用。如果你问我认为你是什么,那么你的答案来自于参数解包

opts.usersChoice = standardGenerator4
opts.usersArguments = (obj, 4.0)

opts.usersChoice(*opts.usersArguments)
这将调用
standardGenerator4(obj,4.0)

您也可以将其用于列表,以便在需要时构建它:

opts.usersChoice = standardGenerator4
opts.usersArguments = [obj]
...
opts.usersArguments.append(4.0)
...
opts.usersChoice(*opts.usersArguments)

也会有同样的结果。

为什么不把它设为一个带有
\uuuu调用\uuu
的类呢

class standardGenerator(object):
    def __init__(self, param=8.0):
        self.param = param
    def __call__(self, obj):
        # do stuff with obj and self.param
用户代码执行以下操作:

opts.usersChoice = standardGenerator() # for default, or...
opts.usersChoice = standardGenerator(4.0)
然后像以前一样,
opts.usersChoice
是可调用的,只有一个参数用于
obj

编辑:如果您有多个函数,并且不想将它们全部转换为类,则可以创建一个包装类:

class wrapper(object):
    def __init__(self, func, **args):
        self.func, self.args = func, args
    def __call__(self, *args):
        return self.func(*args, **self.kwargs)
然后您的旧函数可以像以前一样“原始”使用,或者像这样用于用户定义的参数:

opts.usersChoice = wrapper(standardGenerator, param=4.0)
我认为第一个解决方案更干净,第二个解决方案可能开始复制
functools.partial
,但你明白了

编辑:您可以做的另一件事,可以说是邪恶的,就是使用运算符重载:

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
class\u标准生成器(对象):
定义初始化(self,参数=8.0):
self.param=param

#重载+1,可调用类是一种很好的方法,不过会增加一些复杂性。我已经预料到,我的一些更高级的用户可能希望创建自己的类,并按照您建议的方式来实现。我在这里寻找的是编写一些固定例程并提供一点灵活性的最简单的方法。@amos-你可以通过操作符重载来做一些坏事,但我认为类(或lambda)是最好的方法。我认为问题是用户没有访问
obj
的权限,因此无法将其作为
usersArguments
的一部分传递。我的
opts
对象非常广泛,我在其他情况下也做了类似的事情。如果可以避免的话,我不喜欢参数和函数之间的断开。我不知道这是存在的。这就是我们提问的原因。这里的缺点是,它需要用户了解
部分
是如何工作的,这比
lambda
更加模糊,并且需要
导入
。但是如果我在手册中列举一些例子,也许他们不会抱怨太多…@amos,嗯,我想你说的晦涩是指“不广为人知”,在这种情况下你是对的。但我怀疑,对于那些对
lambda
partial
一无所知的人来说,
partial
可能更容易解释。根据您的用户导入软件包的方式,将
partial
也放入其中应该不会太难。一个值得考虑的问题——也许您应该在
opts
--
usersChoiceParam
中有另一个字段。