Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何让基于类的装饰器为实例方法工作?_Python_Python 2.7_Python 3.x_Decorator - Fatal编程技术网

Python 如何让基于类的装饰器为实例方法工作?

Python 如何让基于类的装饰器为实例方法工作?,python,python-2.7,python-3.x,decorator,Python,Python 2.7,Python 3.x,Decorator,调用decorator有两种方法:1)通过传递decorator函数/类 class Foo(object): def __init__(self): self.x = 1 @foo_decorator def bar(self, x): return self.x + x 或者2)通过传递decorator函数/类实例的返回值 class Foo(object): def __init__(self): sel

调用decorator有两种方法:1)通过传递decorator函数/类

class Foo(object):
    def __init__(self):
        self.x = 1

    @foo_decorator
    def bar(self, x):
        return self.x + x
或者2)通过传递decorator函数/类实例的返回值

class Foo(object):
    def __init__(self):
        self.x = 1

    @foo_decorator("args")
    def bar(self, x):
        return self.x + x
问题是:如果我需要使用基于类的方法实现decorator,那么如何让decorator在这两种情况下都工作

这种实施的一个例子是:

import functools

class FooDecorator(object):
    def __init__(self, *args):
        if len(args) == 1 and callable(args[0]):
            self.f = args[0]
            functools.update_wrapper(self, args[0])
        else:
            self.f = None

    def __call__(self, *args, **kwargs):
        if self.f is not None:
            return self.f(*args, **kwargs)
        else:
            assert len(args) >= 1 and callable(args[0])
            f = args[0]
            self.f = f
            functools.update_wrapper(self, f)

            return self

foo_decorator = FooDecorator
但是,使用以下代码测试此简单实现会产生一些错误:

class Foo1(object):
    def __init__(self):
        self.x = 1

    @foo_decorator
    def bar(self, x):
        return self.x + x

class Foo2(object):
    def __init__(self):
        self.x = 1

    @foo_decorator("args")
    def bar(self, x):
        return self.x + x


Foos = [Foo1, Foo2]

for i in range(2):
    print(Foos[i].__name__)
    f = Foos[i]()
    print(f.bar(10))

Traceback (most recent call last):
  File "python", line 47, in <module>
  File "python", line 13, in __call__
TypeError: bar() missing 1 required positional argument: 'x'
类Foo1(对象):
定义初始化(自):
self.x=1
@富奥装饰师
def条(自身,x):
返回self.x+x
类别2(对象):
定义初始化(自):
self.x=1
@foo_decorator(“args”)
def条(自身,x):
返回self.x+x
Foos=[Foo1,Foo2]
对于范围(2)中的i:
打印(Foos[i]。_名称__)
f=Foos[i]()
印刷品(f.bar(10))
回溯(最近一次呼叫最后一次):
文件“python”,第47行,在
调用中第13行的文件“python”__
TypeError:bar()缺少1个必需的位置参数:“x”
这已经在Python2.7和3.5上进行了测试

感谢您的帮助。请注意,我已经彻底搜索了整个网站,并且已经阅读了以下关于该主题的文章:

另请注意,据我所知,
decorator
包不支持产生decorator(预初始化decorator对象)的第二种方法。

参考和信用:

类方法是(非数据)描述符。如果方法在修饰期间被替换,则必须恢复描述符函数

这对我在Python3上有效<代码>kwargs为简单起见未实现

class Deco:
    def __init__(self, *args):
        if len(args) == 1 and callable(args[0]):
            self._func = args[0]
            self._dargs = None
        else:
            self._func = None
            self._dargs = args

    def __call__(self, *args):
        if self._func is None:
            self._func = args[0]
            return self
        print("decorated with: {}".format(self._dargs))
        return self._func(*args)

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        def bound_decorated(*args):
            return self.__call__(obj, *args)
        return bound_decorated
(无论如何,我更喜欢任何更简单的解决方案。)

–我建议您决定您的函数是否是decorator,还是返回decorator。如果参数是可选的,则将其设置为
@foo_decorator(“args”)
@foo_decorator()
,但在调用中加入“magic”以确定它是用作decorator还是用作函数似乎有点太复杂(并且难以维护)。