如何使用python操作lambda中的函数?

时间:2017-04-25 18:33:17

标签: python function lambda

我想操作一个lambda函数列表。这个lambda函数列表都包含相同的函数,我想操作它,以便其中的函数有一个额外的参数

请参阅下面的示例

def base_function(*args):
    for arg in args:
        print arg

list_of_functions = [
    lambda new_arg: base_function(new_arg,'arg_1'),
    lambda new_arg: base_function(new_arg,'arg_2'),
    lambda new_arg: base_function(new_arg,'arg_3')
]

是否可以将此功能列表更改为以下内容,而无需重写整个功能列表

list_of_functions = [
    lambda new_arg: base_function(new_arg,'arg_1','another_arg'),
    lambda new_arg: base_function(new_arg,'arg_2','another_arg'),
    lambda new_arg: base_function(new_arg,'arg_3','another_arg')
]

请参阅下文,了解我正在尝试做的另一个例子。我有以下内容:

def simple_function(arg,capitalize=False):
    if capitalize:
        print arg.upper()
    else:
        print arg 


list_of_functions = [lambda key_word: simple_function(key_word),lambda key_word: simple_function(key_word)]

但我想将list_of_functions更改为以下内容,而无需重写上面的list_of_functions或simple_function:

desired_list_of_functions = [lambda key_word: simple_function(key_word,capitalize=True),lambda key_word: simple_function(key_word,capitalize=True)]

3 个答案:

答案 0 :(得分:0)

这是我如何使用部分应用程序,如@ austin-hastings所建议的那样:

# first example from the OP

def base_function(*args):
    for arg in args:
        print arg

list_of_functions = [
    lambda new_arg: base_function(new_arg,'arg_1'),
    lambda new_arg: base_function(new_arg,'arg_2'),
    lambda new_arg: base_function(new_arg,'arg_3')
]

# solution:

from functools import partial

new_list_of_functions = [
  partial(fn, 'another_arg') for fn in list_of_functions
]

要将参数放在最后,您可以查看@austin-hastings's solution

当然,您可以使用部分应用程序隐藏list_of_functions。

然后,对于您的特定用例:

desired_list_of_functions = [
  lambda key_word: simple_function(key_word,capitalize=True),
  lambda key_word: simple_function(key_word,capitalize=True)
]

你可以这样做:

desired_list_of_functions = [
    partial(fn, capitalize=True) for fn in list_of_functions
]

那是因为partial将作为参数(fn, *args, **kwargs)作为参数应用于函数。

好的,通过使用引用阴影,可以按如下方式解决您的问题:

def simple_function(arg,capitalize=False):
    if capitalize:
        print (arg.upper())
    else:
        print (arg)


list_of_functions = [lambda key_word: simple_function(key_word),lambda key_word: simple_function(key_word)]

# will print 'foo' twice
for fn in list_of_functions:
    fn('foo')

simple_function = partial(simple_function, capitalize=True)

# will print 'FOO' twice
for fn in list_of_functions:
    fn('foo')

上述hack利用lambda中的list_of_functions定义尚未绑定到simple_function引用这一事实,因为lambda函数的内容尚未执行在运行时。

只有在调用lambda时才会对引用进行赋值,因此lambda中的simple_function引用将指向新的部分实例而不是原始函数实例。

答案 1 :(得分:0)

有点脏的解决方案可能如下:

def simple_function(arg, capitalize=False):
    if capitalize:
        print arg.upper()
    else:
        print arg

#this function takes as its argument a lambda function which
#is assumed to merely call another global function defined within
#the same module  
def transf(l):
    #find out which function is being called from within the lambda
    f = globals()[l.__code__.co_names[0]]

    #return a lambda calling the same function with customized keyword argument
    return lambda arg: f(arg, capitalize=True)

list_of_functions = [lambda key_word: simple_function(key_word),lambda key_word: simple_function(key_word)]

new_list_of_functions = list(map(transf, list_of_functions))

for f in list_of_functions:
    f('x')

for f in new_list_of_functions:
    f('x')

答案 2 :(得分:0)

这是一个子类partial的版本,以便将预先指定的args放在后面。它从您提供的代码开始,然后替换它(主要是因为我可以确认行为):

def base_function(*args):
    for arg in args:
        print arg

list_of_functions = [
    lambda new_arg: base_function(new_arg,'arg_1'),
    lambda new_arg: base_function(new_arg,'arg_2'),
    lambda new_arg: base_function(new_arg,'arg_3')
]

for f in list_of_functions:
    f('x')

import functools

class partial_atend(functools.partial):
    def __call__(self, *args, **kwargs):
        f=self.func
        args += self.args
        kw = self.keywords.copy()
        kw.update(kwargs)
        return f(*args, **kw)

list_of_functions = [
    partial_atend(base_function, 'arg_1'),
    partial_atend(base_function, 'arg_2'),
    partial_atend(base_function, 'arg_3'),
]

# Modify args:
list_of_functions = [ partial_atend(f.func, *(f.args+('another_arg',)), **f.keywords) for f in list_of_functions]

# Make the call:
print "Make the call(s)..."
for f in list_of_functions:
    f('x')

有一件事值得注意:我不想搞砸可能有部分调用partial_atends调用......无论如何。所以我选择扩展列表推导中的参数,然后用一个新的部分对象替换一个部分对象。这将更快(如果重要的话),我认为它不太可能被任何实施细节搞砸。

修改

要解决capitalize=True更新问题,您可以使用keywords属性执行相同操作:

首先,修改base_function以打印kwargs:

def base_function(*args, **kwargs):
    for arg in args:
        print arg
    for k,v in kwargs.items():
        print("{}={}".format(k,v))

然后,附上以下代码:

# Modify kwargs, add `capitalize=True`:
list_of_functions = [ partial_atend(f.func, *f.args, capitalize=True, **f.keywords) for f in list_of_functions]

打印新的lambdas:

print "Make the call(s)...capitalized"
for f in list_of_functions:
    f('x')