在Python中使用语法糖进行函数组合是一个好主意吗?

si1*_*i14 18 python function-composition

前段时间我查看了Haskell文档,发现它的功能组合运算符非常好.所以我实现了这个小装饰:

from functools import partial

class _compfunc(partial):
    def __lshift__(self, y):
        f = lambda *args, **kwargs: self.func(y(*args, **kwargs)) 
        return _compfunc(f)

    def __rshift__(self, y):
        f = lambda *args, **kwargs: y(self.func(*args, **kwargs)) 
        return _compfunc(f)

def composable(f):
    return _compfunc(f)

@composable    
def f1(x):
    return x * 2

@composable
def f2(x):
    return  x + 3

@composable
def f3(x):
    return (-1) * x

@composable
def f4(a):
    return a + [0]

print (f1 >> f2 >> f3)(3) #-9
print (f4 >> f1)([1, 2]) #[1, 2, 0, 1, 2, 0]
print (f4 << f1)([1, 2]) #[1, 2, 1, 2, 0]
Run Code Online (Sandbox Code Playgroud)

问题:没有语言支持,我们不能在内置函数或lambdas上使用这种语法,如下所示:

((lambda x: x + 3) >> abs)(2)
Run Code Online (Sandbox Code Playgroud)

问题:它有用吗?是否值得在python邮件列表上讨论?

Cat*_*lus 8

恕我直言:不,不是.虽然我喜欢Haskell,但这似乎不适合Python.而不是(f1 >> f2 >> f3)你可以做到compose(f1, f2, f3)并解决你的问题 - 你可以使用它与任何可调用,没有任何超载,装饰或更改核心(IIRC有人已经提出functools.compose至少一次;我现在找不到它).

此外,语言定义现在被冻结,所以他们可能会拒绝这种改变 - 参见PEP 3003.

  • @ si14:不知道Haskell我找不到>>和<<清楚(是否意味着插入或包装其他函数?). (2认同)

Mik*_*ham 6

函数组合不是Python中的超常用操作,尤其不是以明显需要组合运算符的方式.如果添加的东西,我不能肯定我喜欢的选择<<,并>>为Python,这是不那么明显对我来说,他们似乎是你.

我怀疑很多人会更熟悉一个函数compose,其顺序不成问题:compose(f, g)(x)意思是f(g(x)),与o数学和.Haskell中的顺序相同.Python试图避免在英语单词使用时使用标点符号,特别是当特殊字符没有广为人知的含义时.(对于那些看起来太有用而无法传递的事情,例如@为装饰者(非常犹豫)和*和**用于函数参数.)

如果你确实选择将它发送给python-ideas,你可能会赢得更多人,如果你能在stdlib或流行的Python库中找到一些实例,那么函数组合可以使代码更清晰,易于编写,可维护,或有效率.


n61*_*007 6

你可以这样做reduce,虽然电话的顺序只是从左到右:

def f1(a):
    return a+1

def f2(a):
    return a+10

def f3(a):
    return a+100

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


reduce(call, (f1, f2, f3), 5)
# 5 -> f1 -> f2 -> f3 -> 116
reduce(call, ((lambda x: x+3), abs), 2)
# 5
Run Code Online (Sandbox Code Playgroud)