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

def square(n): 
    return n * n 

Он мертв легко создавать функции в Python:Как умножить функции в 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] 

К сожалению, при желании использовать композицию в качестве ключа, это своего рода хромым:

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

Это должно действительно просто быть sorted(my_list, key=square*sub3), потому что heck, функция __mul__ не используется ни для чего другого:

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

Хорошо, давайте просто определим это!

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

Эй, теперь мы получаем где-то ..

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

Но я не хочу Hack вызываемую класс! Правила охвата совершенно разные, как я не совсем понимаю, и это даже уродливее, чем «ламеда». Я хочу, чтобы monkeypatch функции . Как я могу это сделать?

+0

никогда не видел ничего подобного этому, вы пробовали, используя 'partials' вместо похож на' Hack' но, возможно, незначительно лучше – dashesy

+0

Почему нет: 'key = lambda n: square (n) * sub3 (n)' –

+4

@MalikBrahimi, который не является составной функцией, чего хочет wim. Http: //en.wikipedia.org/wiki/Function_composition –

ответ

17

Вы можете использовать свой класс хакера как декоратор в значительной степени, так как он написан, хотя вы, вероятно, захотите выбрать более подходящее имя для класса.

Как это:

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 

Вы можете украсить свои функции следующим образом:

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

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

И компоновать их так:

(square * sub3)(n) 

В основном это то же самое, что вы» вы использовали ваш класс взлома, но использовали его как декоратор.

+1

Neat. Я сделал небольшое улучшение, так что теперь композиция работает с любыми другими вызывающими элементами, например '(sub3 * int) (« 10 ») -> 7' и' (str * sub3) (10) -> '7'' – wim

2

Python не поддерживает (и, вероятно, никогда) поддержку композиции композиции на синтаксическом уровне или в качестве стандартной библиотечной функции. Существуют различные сторонние модули (такие как functional), которые обеспечивают функцию более высокого порядка, которая реализует композицию функции.

2

Может быть что-то вроде этого:

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 

И потом:

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

Почему бы не использовать закрытие вместо этого? – Veedrac

+0

Закрытие тоже прекрасное. Я не вижу большой разницы между этими подходами (за исключением того, что с классом вы можете изменять список функций после создания композиции). –

Смежные вопросы