1

Я пытался разработать библиотеку python для использования монадов (игрушечный проект, чтобы понять как монады, так и то, как python может действовать как «чисто функциональный» язык), но этот вопрос не имеет ничего общего с монадами или функциональным программированием.Класс декоративного декоратора Python, демонстрирующий странное поведение

В необходимости оператора сочинить функции, я попытался следующий «декоратора класс»:

class Composable(object): 
    def __init__(self, func): 
     self._func = func 

    def __call__(self, *args): 
     return self._func(*args) 

    def _compose(self, func): 
     @Composable 
     def _func(*args): 
      return func(self._func(*args)) 
     return _func 

    def __mul__(self, func): 
     return self._compose(other) 

Он должен быть использован как внутри метода «_compose», и она работает безупречно, если я использую его для «орфографической функции». То есть, следующий код работает отлично:

@Composable 
def function1(n): 
    return n + 1 

@Composable 
def function2(n): 
    return n * 2 

print((function1 * function2)(5)) #outputs (5 * 2) + 1 = 11 

Дело в том, что я не понимаю, что, если я украсят две функции декораторы с «наборный», я не буду иметь возможность непосредственно создавать их в качестве декораторов , используя «умножение» оператор, как я делал раньше:

@Composable 
def decorator1(func): 
    def decorated(n): 
     return func(n) + 1 
    return decorated 

@Composable 
def decorator2(func): 
    def decorated(n): 
     return func(n) * 2 
    return decorated 

#This triggers a "SyntaxError" (with or without enclosing parentheses) 
@decorator1 * decorator2 
def function(n): 
    return n 

#While this works fine 
@decorator1._compose(decorator2) 
def function(n): 
    return n 

#Not quite surprisingly, this works fine too 
@decorator1.__mul__(decorator2) 

#(as always, this outputs (5 * 2) + 1 = 11) 
function(5) 

Мой пункт: я «было сказано» (см the mul magic method и python decorators), что

a * b 

не так много мо повторно чем синтаксический сахар для

a.__mul__(b) 

и что

@decorator 
def f(n): 
    pass 

это не более чем

def f(n): 
    pass 
f = decorator(f) 

Так вот мой вопрос: что здесь происходит? Не являются ли декораторы результатом оценки любого выражения, которое возвращает вызываемый?

Да, и если кто-нибудь задавался вопросом: я использую python3.5

+0

Я не думаю, что '@ decorator1' в' @ decorator1 * decorator2' является объектом. –

+1

Вы смешиваете соль в синтаксическом сахаре! Нет, вы не можете размножать декораторы при использовании синтаксиса '@'; вы можете увидеть [в ссылке на язык] (https://docs.python.org/3/reference/compound_stmts.html#function-definitions), что это не юридическая грамматика. – jonrsharpe

+1

См. Также [PEP 318] (https: //www.python.org/dev/peps/pep-0318/# id30): «Утверждение декоратора ограничено тем, что он может принять, - произвольные выражения не будут работать» –

ответ

1

language reference обеспечивает грамматику для декоратора:

decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE 

Оба decorator1._compose и decorator1.__mul__ грамматически dotted_name s, следовательно, действительный синтаксис. @decorator1 * decorator2, однако, явно не соответствует.

«Синтаксический сахар» не означает, что вы можете напрямую заменить детали одной формы на части другого. Форма:

@decorator 
def f(n): 
    pass 

конечно эквивалентно:

def f(n): 
    pass 
f = decorator(f) 

, но они не являются одинаковыми и не являются полностью взаимозаменяемыми.

+0

Я вижу. Вот почему @ (decorator1 * decorator2) Функция def (n): Пропуск также содержит ошибку? – LorenzoPerticone

+0

@ LorenzoPerticone yes; у вас не может быть произвольных выражений, а только точечное имя, которое необязательно может быть заключено в круглые скобки, которые сами по себе могут содержать аргументы. – jonrsharpe