Python 装饰器使用静态方法。但使用 2 个静态方法失败。为啥?

Posted

技术标签:

【中文标题】Python 装饰器使用静态方法。但使用 2 个静态方法失败。为啥?【英文标题】:Python decorator works with staticmethod. But fails with 2 static methods. Why?Python 装饰器使用静态方法。但使用 2 个静态方法失败。为什么? 【发布时间】:2016-02-17 04:23:27 【问题描述】:

这是我的 Python 代码。我有一个类MyClass 有两个静态方法:my_method1my_method2。这两种方法都使用名为 exception_handler 的装饰器包装。

from functools import wraps
import sys

def exception_handler(function):
    @wraps(function)
    def decorator(self, *args, **kwargs):
        try:
            return function(self, *args, **kwargs)
        except Exception, e:
            print "EXCEPTION!: %s" % e
            sys.exit(-1)
    return decorator


class MyClass:
    @staticmethod
    @exception_handler
    def my_method1(a, b, c,):
        return "X"

    @staticmethod
    @exception_handler
    def my_method2(e, f, g,):
        print "Y"
        return MyClass.my_method1(a=e, b=f, c=g)

print "Trying my_method1"
print MyClass.my_method1(1, 2, 3)

print ""
print "Trying my_method2"
print MyClass.my_method2(1, 2, 3)

当我运行这段代码时,我得到以下信息:

Trying my_method1
X

Trying my_method2
Y
EXCEPTION!: decorator() takes at least 1 argument (0 given)

为什么装饰器在第二种情况下会失败,我该如何解决?

当装饰方法是被另一个静态方法调用的静态方法时,装饰器似乎失败了。但是为什么会发生这种情况对我来说毫无意义。

【问题讨论】:

为什么内部函数中有一个“自我”?静态方法不会将 self 或 cls 作为第一个参数 except Exception, e::如果可能,请使用except Exception as e:。这个语法一直是deprecated since Python 2.6。 奥兹。此装饰器旨在用于静态方法和非静态类方法。它对两者都有效......直到我尝试从另一个包装的静态方法中调用一个包装的静态方法。 感谢 Evert 指出这一点。我会做出改变。 【参考方案1】:

问题在于staticmethods 没有将self 作为参数。我不确定为什么它适用于前两个电话而不是第三个电话。但是,从装饰器中删除 self 可以修复它。

这是重构后的代码:

from functools import wraps
import sys


def exception_handler(function):
    @wraps(function)
    def decorator(*args, **kwargs):
        try:
            return function(*args, **kwargs)
        except Exception as e:
            print "EXCEPTION!: ".format(e)
            sys.exit(-1)

    return decorator


class MyClass(object):
    @staticmethod
    @exception_handler
    def my_method1(a, b, c, ):
        return "X"

    @staticmethod
    @exception_handler
    def my_method2(e, f, g, ):
        print "Y"
        return MyClass.my_method1(a=e, b=f, c=g)


print "Trying my_method1"
print MyClass.my_method1(1, 2, 3)

print
print "Trying my_method2"
print MyClass.my_method2(1, 2, 3)

这样做会产生以下结果:

Trying my_method1
X

Trying my_method2
Y
X

【讨论】:

所以我想要一个这样的装饰器,用于静态和非静态方法的异常处理。我只需要两个不同的装饰器吗? 是的。否则,您将需要像这样调用静态方法:MyClass.my_method1(_, 1, 2, 3) ...【参考方案2】:

我认为您的代码在您没有注意到的情况下失败了,您可以尝试打印您的 a, b, c *args 吗?你会发现aself !!!所以它通过分配错误的参数默默地失败。

那么为什么它在这里第二次调用时引发异常:MyClass.my_method1(a=e, b=f, c=g) 那是因为你的 *args 现在是空的,并且 self 不能像以前那样替换任何变量。

【讨论】:

以上是关于Python 装饰器使用静态方法。但使用 2 个静态方法失败。为啥?的主要内容,如果未能解决你的问题,请参考以下文章

Python functools.partial - 如何使用静态装饰器将其应用于类方法

python的内置装饰器

python的内置装饰器

Python的静态方法和类方法

32.Python面向对象描述符运算符底层装饰器:闭包-闭包参数-内置装饰器-类装饰器

32.Python面向对象描述符运算符底层装饰器:闭包-闭包参数-内置装饰器-类装饰器