Is it a good idea to have a syntax sugar to function composition in Python?

后端 未结 4 683
我寻月下人不归
我寻月下人不归 2021-02-05 08:37

Some time ago I looked over Haskell docs and found it\'s functional composition operator really nice. So I\'ve implemented this tiny decorator:

from functools im         


        
相关标签:
4条回答
  • 2021-02-05 09:02

    Function composition isn't a super-common operation in Python, especially not in a way that a composition operator is clearly needed. If something was added, I am not certain I like the choice of << and >> for Python, which are not as obvious to me as they seem to be to you.

    I suspect a lot of people would be more comfortable with a function compose, the order of which is not problematic: compose(f, g)(x) would mean f(g(x)), the same order as o in math and . in Haskell. Python tries to avoid using punctuation when English words will do, especially when the special characters don't have widely-known meaning. (Exceptions are made for things that seem too useful to pass up, such as @ for decorators (with much hesitation) and * and ** for function arguments.)

    If you do choose to send this to python-ideas, you'll probably win a lot more people if you can find some instances in the stdlib or popular Python libraries that function composition could have made code more clear, easy to write, maintainable, or efficient.

    0 讨论(0)
  • 2021-02-05 09:07

    IMHO: no, it's not. While I like Haskell, this just doesn't seem to fit in Python. Instead of (f1 >> f2 >> f3) you can do compose(f1, f2, f3) and that solves your problem -- you can use it with any callable without any overloading, decorating or changing the core (IIRC somebody already proposed functools.compose at least once; I can't find it right now).

    Besides, the language definition is frozen right now, so they will probably reject that kind of change anyway -- see PEP 3003.

    0 讨论(0)
  • 2021-02-05 09:14

    You can do it with reduce, although the order of calls is left-to-right only:

    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
    
    0 讨论(0)
  • 2021-02-05 09:17

    I don't have enough experience with Python to have a view on whether a language change would be worthwhile. But I wanted to describe the options available with the current language.

    To avoid creating unexpected behavior, functional composition should ideally follow the standard math (or Haskell) order of operations, i.e., f ∘ g ∘ h should mean apply h, then g, then f.

    If you want to use an existing operator in Python, say <<, as you mention you'd have a problem with lambdas and built-ins. You can make your life easier by defining the reflected version __rlshift__ in addition to __lshift__. With that, lambda/built-ins adjacent to composable objects would be taken care of. When you do have two adjacent lambda/built-ins, you'll need to explicitly convert (just one of) them with composable, as @si14 suggested. Note I really mean __rlshift__, not __rshift__; in fact, I would advise against using __rshift__ at all, since the order change is confusing despite the directional hint provided by the shape of the operator.

    But there's another approach that you may want to consider. Ferdinand Jamitzky has a great recipe for defining pseudo infix operators in Python that work even on built-ins. With this, you can write f |o| g for function composition, which actually looks very reasonable.

    0 讨论(0)
提交回复
热议问题