【问题标题】:Python custom decorator class exhibiting strange behaviourPython 自定义装饰器类表现出奇怪的行为
【发布时间】:2017-05-30 18:27:11
【问题描述】:

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

由于需要一个算子来组合函数,我尝试了下面的“装饰类”:

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”装饰两个函数装饰器,我将无法像以前那样使用“乘法”运算符直接将它们组合为装饰器:

@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

【问题讨论】:

  • 我不认为@decorator1 * decorator2 中的@decorator1 是一个对象。
  • 你在语法糖中混入了盐!不,当使用 @ 语法时,你不能乘以装饰器;你可以看到in the language reference这不是合法的语法。
  • 另见PEP 318:“装饰器语句的接受范围有限——任意表达式都不起作用”

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


【解决方案1】:

language reference 提供了装饰器的语法:

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

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

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

@decorator
def f(n):
    pass

当然等价于

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

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

【讨论】:

  • 我明白了。这就是为什么 @(decorator1 * decorator2) def function(n): pass 也会报错吗?
  • @LorenzoPerticone 是的;你不能有任意的表达式,只能有一个带点的名称,后面可以选择带括号,它们本身可以包含参数。
猜你喜欢
  • 2019-10-14
  • 2021-07-11
  • 2021-12-01
  • 1970-01-01
  • 2016-07-14
  • 1970-01-01
  • 2012-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多