【问题标题】:How can I use an operator to compose functions?如何使用运算符来组合函数?
【发布时间】:2019-06-06 18:56:36
【问题描述】:

编写一个由其他两个函数组成的函数相当简单。 (为简单起见,假设它们都是一个参数。)

def compose(f, g):
    fg = lambda x: f(g(x))
    return fg

def add1(x):
    return x + 1

def add2(x):
    return x + 2

print(compose(add1, add2)(5))  # => 8

我想使用运算符进行合成,例如,(add1 . add2)(5)

有没有办法做到这一点?

我尝试了各种装饰器配方,但都无法使用。

def composable(f):
  """
    Nothing I tried worked. I won't clutter up the question 
    with my failed attempts.
  """

@composable
def add1(x):
    return x + 1

【问题讨论】:

标签: python-3.x python-decorators function-composition


【解决方案1】:

首先,Python 语法中只允许使用一定数量的运算符符号。点“.”不是有效的运算符。

This page(该页面实际上是关于 Python operator 模块,但命名约定与datamodel 相同,内容更有条理)列出了所有可用的运算符和对应的实例方法。例如,如果你想使用“@”作为操作符,你可以这样写一个装饰器:

import functools

class Composable:

    def __init__(self, func):
        self.func = func
        functools.update_wrapper(self, func)

    def __matmul__(self, other):
        return lambda *args, **kw: self.func(other.func(*args, **kw))

    def __call__(self, *args, **kw):
        return self.func(*args, **kw)

测试:

@Composable
def add1(x):
    return x + 1

@Composable
def add2(x):
    return x + 2

print((add1 @ add2)(5))
# 8

【讨论】:

  • 谢谢。我的困惑——至少其中之一——是 dot 被视为运算符,而 getattribute 是关联函数。另外,我试图用装饰器函数而不是装饰器类来做到这一点。我暂时不选择您的解决方案作为答案,看看是否建议了另一种方法。
  • @RussAbbott 我明白你的意思。我不认为你可以重新加载__getattribute__ 方法来访问另一个函数而不直接传递另一个函数。确实可以通过globals()访问全局函数,但不推荐,而且根本无法处理匿名函数。
  • 我遇到的一个问题是 getattribute 似乎将它的参数作为字符串获取——即使我向它传递了一个函数。不知道如何解决。
  • 我刚刚尝试了您解决方案的装饰器功能版本。当它到达print((add1 @ add2)(5)) 时,我收到一条错误消息:unsupported operand type(s) for @: 'function' and 'function'。你的方法如何避免遇到这个问题?
  • 如果我将 @ 替换为 *__matmul__ 替换为 __mul__ 或使用 > 和 .__gt__ (即使 PyCharm 抱怨boolean 是不可调用的。)但正如我之前所说,使用 .__getattribute__ 失败,因为 __getattribute__ 的参数在传递给 __getattribute__ 之前被转换为字符串。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-09
  • 2021-12-25
  • 2015-05-10
  • 1970-01-01
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
相关资源
最近更新 更多