组合函数与函数模块

14 投票
1 回答
6076 浏览
提问于 2025-04-17 10:55

Python 3.2 的文档提到了Collin Winter 的 functional 模块,这个模块里有一个叫 compose 的函数:

compose() 函数实现了函数组合。简单来说,它的作用是把一个函数的输出直接作为另一个函数的输入。

不过,这个模块自2006年7月以来就没有更新了,我在想有没有其他的替代方案。

目前,我只需要 compose 这个函数。请问下面这个原始的 functional.compose 定义在 Python 3 中还好用吗?

def compose(func_1, func_2, unpack=False):
    """
    compose(func_1, func_2, unpack=False) -> function

    The function returned by compose is a composition of func_1 and func_2.
    That is, compose(func_1, func_2)(5) == func_1(func_2(5))
    """
    if not callable(func_1):
        raise TypeError("First argument to compose must be callable")
    if not callable(func_2):
        raise TypeError("Second argument to compose must be callable")

    if unpack:
        def composition(*args, **kwargs):
            return func_1(*func_2(*args, **kwargs))
    else:
        def composition(*args, **kwargs):
            return func_1(func_2(*args, **kwargs))
    return composition

这个SO 问题有点相关;它在问 Python 是否应该支持 compose 的特殊语法。

1 个回答

6

你实现的 compose 在 Python 3.2 中是有效的,正如上面的评论所讨论的那样。

你提到的库中的大部分函数在 Python 中都有对应的实现,可以在文档中找到。

mapfilter 这样的函数在 Python 中已经实现,并且可以用列表推导式简单表示。Python 还有一个 id 函数,可以返回对象的身份(以整数形式),而库中的 id 函数可以用 lambda x: x 来表示。

你可能会对 itertoolsfunctools 模块感兴趣,它们包含了 partialreduce 函数(reduce 类似于 foldl,但参数的顺序不同)。

这里有一些我在标准库中没有找到的简单实现:

from functools import reduce

def flip(f):
    if not callable(f):
        raise TypeError("Cannot filp a non-callable object")
    def result(*args, **kw):
        args = list(args)
        args.reverse()
        return f(*args, **kw)
    return result

def ilast(i):
    return reduce(lambda _, x: x, i)

def iscanl(f, v, seq):
    yield v
    for a in seq:
        v = f(v, a)
        yield v

def scanl(*args, **kw):
    return list(iscanl(*args, **kw))

def foldl(*args, **kw):
    return ilast(iscanl(*args, **kw))
# Or using reduce
#def foldl(f, v, seq):
#    return reduce(f, seq, v)

def iscanr_reverse(f, v, seq):
    return iscanl(flip(f), v, seq)

def scanr(*args, **kw):
    result = list(iscanr_reverse(*args, **kw))
    result.reverse()
    return result

def foldr(*args, **kw):
    return ilast(iscanr_reverse(*args, **kw))

撰写回答