18

是否有任何干净的方法可以在没有 lambda 或列表理解的情况下在 Python 中的对象上应用函数列表?就像 Haskell 表达式:

map ($ obj) [foo1,foo2]

Python中的lambda示例:

response = map(lambda foo:foo(obj),[foo1,foo2]) #fooX:object->Bool

它可以扩展到类函数吗?

也许来自运营商或 itertools 的东西?

4

7 回答 7

16

您总是可以创建一个函数来为您处理它:

def map_funcs(obj, func_list):
    return [func(obj) for func in func_list]

    # I was under the impression that the OP wanted to compose the functions,
    # i.e. f3(f2(f1(f0(obj))), for which the line below is applicable:
    # return reduce(lambda o, func: func(o), func_list, obj)


map_funcs(it, [Buy, Use, Break, Fix])
于 2012-07-31T09:11:30.483 回答
11

我认为这应该符合您的“功能”标准,要回答您的问题,我认为没有一种干净的方法,您应该适应列表理解。

正如@JFSebastian 所建议的那样

>>> from operator import methodcaller
>>> funcs = (lambda x: x + 1, lambda x: x + 2)
>>> obj = 5
>>> list(map(methodcaller('__call__', obj), funcs))
[6, 7]

这是一种疯狂的做法:

>>> from itertools import starmap, repeat
>>> from types import FunctionType
>>> funcs = (lambda x: x + 1, lambda x: x + 2)
>>> obj = 5
>>> list(starmap(FunctionType.__call__, zip(funcs, repeat(obj))))
[6, 7]

正如@AleksiTorhamo 所建议的那样

>>> from itertools import repeat
>>> from types import FunctionType
>>> obj = 5
>>> funcs = (lambda x: x + 1, lambda x: x + 2)
>>> list(map(FunctionType.__call__, funcs, repeat(obj)))
[6, 7]
于 2012-07-31T09:24:00.643 回答
9

问题是缺少的$运算符,它由以下简单定义

def apply(f, a):
    return f(a)

然后可以($ obj)像这样在python中使用部分进行currying:partial(apply, a=obj)

有了这个,我们可以做一个地图应用

map(partial(apply, a=obj), [foo1, foo2]))
于 2013-12-30T11:38:35.010 回答
5

我认为列表推导是基于另一个列表构建一个列表的最佳方式。从列表中应用常规函数非常容易:

results = [f(obj) for f in funcList]

如果您一次不需要整个结果列表,而只需要一次迭代一个项,则生成器表达式可能会更好:

genexp = (f(obj) for f in funcList)
for r in genexp:
    doSomething(r)

如果您的函数是方法,而不是基本函数,则有两种方法:

使用绑定方法,在这种情况下,您在进行函数调用时根本不需要提供对象:

obj = SomeClass()
funcList = [obj.foo1, obj.foo2]
results = [f() for f in funcList]

或者使用未绑定的方法,它们是简单的常规函数​​,它们需要一个定义它们的类的实例作为它们的第一个参数(通常命名为self):

funcList = [SomeClass.foo1, SomeClass.foo2]
obj = SomeClass()
results = [f(obj) for f in funcList]

当然,如果你不需要捕获函数的结果,最简单的方法是简单地写一个循环:

for f in funcList:
    f(obj)
于 2012-07-31T09:10:29.300 回答
1

该库toolz有一个compose功能可以做到这一点。

from toolz import compose
compose(foo1, foo2)(obj)

于 2020-02-09T17:49:11.067 回答
0

这是我的解决方案:

def plus(i):
    return i+i

def mult(i):
    return i*4

functions = [plus,mult]

result=[]

for i in ["a","b","c","d"]:
    for j in functions:
        result.append(j(i))

结果输出[16]:['aa','aaaa','bb','bbbb','cc','cccc','dd','dddd']

于 2019-10-10T17:10:37.107 回答
0

我认为这个问题可以通过两种方式阅读,将函数列表应用于对象并产生列表中每个函数的结果(单输入,多输出按顺序将函数列表应用于对象(单输入,单输出)。

后者由 compose 函数解决,或者通过定义您自己的函数来解决:

def compz(t, funcs):
  return t if not funcs else compz(funcs[0](t), funcs[1:])

print(compz("str", [lambda x: x+"A", lambda x: x+"B", lambda x: x+"C"]))
print(compz("Hello, World", [lambda x: f"<h1>{x}</h1>", lambda x: f"<body>{x}</body>", lambda x: f"<html>{x}</html>",]))
print(compz(2, [lambda x: x+2, lambda x: x+5, lambda x: x+7]))
print(compz(2, [lambda x: x**2, lambda x: x**2, lambda x: x**2]))
print(compz(2, [lambda x: x**2, lambda x: x**2]))
print(compz(2, [lambda x: x**2]))
print(compz(2, []))

strABC
<html><body><h1>Hello, World</h1></body></html>
16
256
16
4
2

后者的大多数答案都是等价的,但实际上是列表理解,因为这些函数不是按顺序“并行”应用的,或者因为您必须导入单独的库。查看一些答案,这可能取决于您的结果应该是什么样子,即您可以拥有

func_list = [lambda x: x+"A", lambda x: x+"B", lambda x: x+"C"]

print([f("str") for f in func_list])
print([f for f in map(lambda f: f("str"), func_list)])

from functools import partial

def apply(f, a):
    return f(a)
  
print([f for f in map(partial(apply, a="str"), func_list)])

def map_funcs(obj, func_list):
    return [func(obj) for func in func_list]

print(map_funcs("str", func_list))

在所有这些情况下,结果是:

['strA', 'strB', 'strC']
于 2021-09-09T14:34:58.777 回答