Python自定义装饰器类表现出奇怪的行为

时间:2017-01-15 23:31:46

标签: python-3.x python-decorators higher-order-functions magic-methods

我正在尝试开发一个使用monads的python库(一个玩具项目来理解monad以及python如何充当“纯功能”语言),但这个问题与monad或函数式编程无关。 / p>

由于操作员需要编写函数,我尝试了以下“装饰器类”:

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”装饰两个函数装饰器,我将无法直接将它们组成装饰器,使用像之前我所做的“乘法”运算符: / p>

@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 methodpython decorators

a * b

不仅仅是语法糖

a.__mul__(b)

那个

@decorator
def f(n):
    pass

只不过是

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

所以这是我的问题:这里发生了什么?装饰器不是评估任何返回可调用的表达式的结果吗?

哦,如果有人想知道:我正在使用python3.5

1 个答案:

答案 0 :(得分:1)

language reference提供装饰器的语法:

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

decorator1._composedecorator1.__mul__都是语法dotted_name,因此这是有效的语法。但是,@decorator1 * decorator2显然不匹配。

“语法糖”并不意味着能够直接用一种形式的部分替换另一种形式的部分。表格:

@decorator
def f(n):
    pass

当然等同于

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

但它们并不相同,也不完全可以互换。