2015-05-12 20 views
26
def sub3(n): 
    return n - 3 

def square(n): 
    return n * n 

Đó là chết dễ dàng thao tác các chức năng trong python:Làm thế nào để nhân các hàm trong 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] 

Thật không may, khi muốn sử dụng các thành phần như một chính, nó là loại què:

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

nên Đây thực sự chỉ là sorted(my_list, key=square*sub3), vì heck, chức năng __mul__ không được sử dụng cho bất kỳ mục đích nào khác:

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

Chúng ta hãy định nghĩa nó sau đó!

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

D'oh!

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

D'oh!

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) 

Hey, bây giờ chúng tôi đang nhận được ở đâu đó ..

>>> 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] 

Nhưng tôi không muốn có một lớp callable Hack! Các quy tắc phạm vi là hoàn toàn khác nhau theo những cách tôi không hiểu đầy đủ, và điều này thậm chí còn xấu hơn so với "lameda" được cho là. Tôi muốn monkeypatch các chức năng . Làm thế nào tôi có thể làm điều đó?

+0

chưa bao giờ thấy bất cứ điều gì tương tự như sau, có bạn đã cố gắng sử dụng 'partials' thay vào đó, tương tự cho' Hack' nhưng có lẽ nhẹ tốt hơn – dashesy

+0

Tại sao không: 'key = lambda n: square (n) * sub3 (n)' –

+4

@MalikBrahimi không phải là thành phần chức năng, đó là những gì wim muốn. http: //en.wikipedia.org/wiki/Function_composition –

Trả lời

17

Bạn có thể sử dụng lớp học hack của mình làm trang trí khá nhiều như được viết, mặc dù bạn có thể muốn chọn tên phù hợp hơn cho lớp học.

Như thế này:

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 

Sau đó, bạn có thể trang trí chức năng của bạn như vậy:

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

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

Và soạn họ như vậy:

(square * sub3)(n) 

Về cơ bản nó là điều tương tự bạn' đã hoàn thành bằng cách sử dụng lớp hack của bạn, nhưng sử dụng nó như là một trang trí.

+1

Gọn gàng. Tôi đã thực hiện một cải tiến nhỏ, vì vậy bây giờ thành phần làm việc với bất kỳ callables khác ví dụ '(sub3 * int) (" 10 ") -> 7' và' (str * sub3) (10) -> '7'' – wim

2

Python không (và có khả năng sẽ không bao giờ) có hỗ trợ cho thành phần chức năng ở cấp độ cú pháp hoặc chức năng thư viện chuẩn. Có nhiều mô-đun bên thứ 3 khác nhau (chẳng hạn như functional) cung cấp chức năng bậc cao hơn thực hiện thành phần chức năng.

2

Có lẽ một cái gì đó như thế này:

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 

Và sau đó:

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

Tại sao không sử dụng một đóng cửa để thay thế? – Veedrac

+0

Đóng cũng được. Tôi không thấy nhiều sự khác biệt giữa các cách tiếp cận đó (ngoại trừ với lớp, bạn có thể sửa đổi danh sách hàm sau khi tạo thành phần). –

Các vấn đề liên quan