10

Tôi làm việc bằng Python. Gần đây, tôi đã khám phá ra một gói nhỏ tuyệt vời có tên là fn. Tôi đã sử dụng nó cho thành phần chức năng.Thành phần chức năng tốt hơn trong Python

Ví dụ, thay vì:

baz(bar(foo(x)))) 

với fn, bạn có thể viết:

(F() >> foo >> bar >> baz)(x) . 

Khi tôi thấy điều này, tôi ngay lập tức nghĩ đến Clojure:

(-> x foo bar baz) . 

Nhưng chú ý, trong Clojure, đầu vào nằm ở bên trái. Tôi tự hỏi nếu điều này có thể trong python/fn.

+2

Trong khi các nhà điều hành quá tải hành vi là thú vị, với tôi đây chỉ có vẻ như là một điều xấu để làm trong mã thực. –

+0

Không có cách nào để làm cho cú pháp chính xác đó hoạt động trong Python, nếu đó là những gì bạn đang yêu cầu. Bạn có thể ước tính nó theo nhiều cách khác nhau. Chính xác những gì là quan trọng đối với bạn cú pháp khôn ngoan? – BrenBarn

+0

Giữ luồng từ trái sang phải.Hiện tại, đối số của hàm tổng hợp là ở cuối. Sẽ rõ ràng hơn nếu tôi có thể viết F() >> x >> foo >> bar >> baz, hoặc tương tự. –

Trả lời

9

Bạn không thể tái tạo cú pháp chính xác, nhưng bạn có thể làm một cái gì đó tương tự:

def f(*args): 
    result = args[0] 

    for func in args[1:]: 
     result = func(result) 

    return result 

Dường như làm việc:

>>> f('a test', reversed, sorted, ''.join) 
' aestt' 
2

Bạn không thể nhận được rằng cú pháp chính xác, mặc dù bạn có thể nhận được một cái gì đó như F(x)(foo, bar, baz). Dưới đây là một ví dụ đơn giản:

class F(object): 
    def __init__(self, arg): 
     self.arg = arg 

    def __call__(self, *funcs): 
     arg = self.arg 
     for f in funcs: 
      arg = f(arg) 
     return arg 

def a(x): 
    return x+2 
def b(x): 
    return x**2 
def c(x): 
    return 3*x 

>>> F(2)(a, b, c) 
48 
>>> F(2)(c, b, a) 
38 

Đây là một chút khác biệt so với câu trả lời của Máy xay sinh tố vì nó lưu trữ các lập luận, có thể sau đó được tái sử dụng với chức năng khác nhau.

Điều này giống như ứng dụng chức năng bình thường: thay vì chỉ định hàm lên phía trước và để lại một số đối số được chỉ định sau, bạn chỉ định đối số và để (các) hàm được chỉ định sau. Đó là một món đồ chơi thú vị nhưng thật khó để nghĩ tại sao bạn thực sự muốn điều này.

1

Nếu bạn muốn sử dụng fn, với một ít hack bạn có thể nhận được một chút gần gũi hơn với Clojure cú pháp:

>>> def r(x): return lambda: x 
>>> (F() >> r(x) >> foo >> bar >> baz)() 

Xem cách tôi đã thêm chức năng khác vào đầu chuỗi thành phần mà chỉ sẽ trở lại x khi được gọi. Vấn đề với điều này là bạn vẫn phải gọi hàm tổng hợp của bạn, mà không cần bất kỳ đối số nào.

Tôi nghĩ @ Câu trả lời của Blender là đặt cược tốt nhất của bạn đang cố gắng mô phỏng chức năng chuỗi của Clojure bằng Python.

0

tôi đến với điều này

def _composition(arg, *funcs_and_args): 
    """ 
    _composition(
     [1,2,3], 
     (filter, lambda x: x % 2 == 1), 
     (map, lambda x: x+3) 
    ) 
    #=> [4, 6] 
    """ 
    for func_and_args in funcs_and_args: 
     func, *b = func_and_args 
     arg = func(*b, arg) 
    return(arg) 
0

Điều này dường như làm việc cho đầu vào đơn giản. Không chắc chắn nó có giá trị nỗ lực cho đầu vào phức tạp, ví dụ: ((42, 'spam'), {'spam': 42}).

def compose(function, *functions): 
    return function if not functions else \ 
      lambda *args, **kwargs: function(compose(*functions)(*args, **kwargs)) 

def rcompose(*functions): 
    return compose(*reversed(functions)) 

def postfix(arg, *functions): 
    return rcompose(*functions)(arg) 

Ví dụ:

>>> postfix(1, str, len, hex) 
'0x1' 
>>> postfix(1, hex, len) 
3 
Các vấn đề liên quan