【问题标题】:How to multiply functions in python?如何在python中乘以函数?
【发布时间】:2015-07-23 13:45:37
【问题描述】:
def sub3(n):
    return n - 3

def square(n):
    return n * n

用 Python 编写函数很容易:

>>> my_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [square(sub3(n)) for n in my_list]
[9, 4, 1, 0, 1, 4, 9, 16, 25, 36]

不幸的是,要将组合用作 key 这很尴尬,您必须在 另一个 函数中使用它们,该函数依次调用这两个函数:

>>> sorted(my_list, key=lambda n: square(sub3(n)))
[3, 2, 4, 1, 5, 0, 6, 7, 8, 9]

这应该只是 sorted(my_list, key=square*sub3),因为见鬼,函数 __mul__ 无论如何都不会用于其他任何事情:

>>> square * sub3
TypeError: unsupported operand type(s) for *: 'function' and 'function'

那么让我们定义它吧!

>>> type(sub3).__mul__ = 'something'
TypeError: can't set attributes of built-in/extension type 'function'

天哪!

>>> class ComposableFunction(types.FunctionType):
...     pass
...
TypeError: Error when calling the metaclass bases
    type 'function' is not an acceptable base type

天哪!

class Hack(object):
    def __init__(self, function):
        self.function = function
    def __call__(self, *args, **kwargs):
        return self.function(*args, **kwargs)
    def __mul__(self, other):
        def hack(*args, **kwargs):
            return self.function(other(*args, **kwargs))
        return Hack(hack)

嘿,现在我们到了某个地方..

>>> square = Hack(square)
>>> sub3 = Hack(sub3)
>>> [square(sub3(n)) for n in my_list]
[9, 4, 1, 0, 1, 4, 9, 16, 25, 36]
>>> [(square*sub3)(n) for n in my_list]
[9, 4, 1, 0, 1, 4, 9, 16, 25, 36]
>>> sorted(my_list, key=square*sub3)
[3, 2, 4, 1, 5, 0, 6, 7, 8, 9]

但我不想要 Hack 可调用类!范围规则在我不完全理解的方式上有所不同,并且可以说它比仅使用“lameda”更难看。是否有可能让合成以某种方式直接与函数一起工作?

【问题讨论】:

  • @MalikBrahimi 这不是函数组合,这正是 wim 想要的。 en.wikipedia.org/wiki/Function_composition
  • 有一个关于添加函数组合的long线程(使用即将推出的矩阵乘法运算符@,因为函数组合更类似于矩阵乘法而不是常规乘法) python-ideas 邮件列表。不过,简短的总结是,它不会很快发生,如果有的话。
  • 这里是a link 到五月的档案。后面有点混乱,因为启动线程的initial message 没有主题,并且它以 2 或 3 个并行线程结束。弹出的一个更有趣的想法(IMO)不是实际组合函数,而是使函数的 tuple 可调用,以便 (f, g, h)(x) == f(g(h(x))).
  • 任何摆脱 (stacks (of (parens (to (balance!)))))))
  • 我不想这么说,但我没有发现 lambda 有什么问题。虽然可调用元组会很酷。

标签: python function monkeypatching function-composition


【解决方案1】:

您可以按照编写的方式将 hack 类用作装饰器,但您可能希望为该类选择更合适的名称。

像这样:

class Composable(object):
    def __init__(self, function):
        self.function = function
    def __call__(self, *args, **kwargs):
        return self.function(*args, **kwargs)
    def __mul__(self, other):
        @Composable
        def composed(*args, **kwargs):
            return self.function(other(*args, **kwargs))
        return composed
    def __rmul__(self, other):
        @Composable
        def composed(*args, **kwargs):
            return other(self.function(*args, **kwargs))
        return composed

然后你可以像这样装饰你的函数:

@Composable
def sub3(n):
    return n - 3

@Composable
def square(n):
    return n * n

然后像这样组合它们:

(square * sub3)(n)

基本上,这与您使用 hack 类完成的事情相同,但将其用作装饰器。

【讨论】:

  • 整洁。我做了一点改进,所以现在组合可以与任何其他可调用对象一起使用,例如 (sub3*int)("10") --> 7(str*sub3)(10) --> '7'
【解决方案2】:

Python 不(并且可能永远不会)在语法级别或作为标准库函数支持函数组合。有各种 3rd 方模块(例如functional)提供了实现函数组合的高阶函数。

【讨论】:

    【解决方案3】:

    可能是这样的:

    class Composition(object):
        def __init__(self, *args):
            self.functions = args
    
        def __call__(self, arg):
            result = arg
            for f in reversed(self.functions):
                result = f(result)
    
            return result
    

    然后:

    sorted(my_list, key=Composition(square, sub3))
    

    【讨论】:

    • 为什么不使用闭包呢?
    • 关闭也很好。我认为这些方法之间没有太大区别(除了使用类,您可以在组合创建后修改函数列表)。
    【解决方案4】:

    您可以使用SSPipe library 编写函数:

    from sspipe import p, px
    
    sub3 = px - 3
    square = px * px
    composed = sub3 | square
    print(5 | composed)
    

    【讨论】:

      猜你喜欢
      • 2018-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-17
      • 2011-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多