如何检索原始@classmethod,@ stestmethod或@property

时间:2012-03-02 02:11:09

标签: python

据我所知,@ decorator.decorator不允许在@staticmethod,@ classmethod(也许还有@property)之上进行装饰。我理解用法:

class A(object):
    @classmethod
    @mydecorator
    def my_method(cls): pass

但是,在调试模块中,我仍然想尝试动态地执行它。所以我想知道从那些描述符(?)中检索原始方法的方法是什么。我读过很少的回复,但我还是很困惑......

我看到一个类的示例,并检索:

class my_class(property):
    def __get__(self, obj, cls):
        return self.fget.__get__(None, cls)

我喜欢装饰的签名保留,但仍不确定如何做到这一点。我试图实现的逻辑是:

import decorator

def mydecorator(f, *d_args, **d_kwargs):
    if (isinstance(f, classmethod)):
        return classmethod(mydecorator(f.__get__.?WHATELSE?))
    elif (isinstance(f, staticmethod)):
        return staticmethod(mydecorator(f.__get__.?WHATELSE?))
    elif (isinstance(f, property)):
        return property(mydecorator(f.__get__.?WHATELSE?))
    else:
        return decorator.decorator(f)

我正在尝试在Python 2.6中执行此操作,所以我也欢迎在未来的python版本中指出@decorator已更改(更正?)。

感谢。

3 个答案:

答案 0 :(得分:8)

考虑到:

>>> def original():pass

>>> classmethod(original).__func__ == original
True
>>> staticmethod(original).__func__ == original
True
>>> property(original).fget == original
True

你的功能应该是这样的:

import decorator

def mydecorator(f, *d_args, **d_kwargs):
    if (isinstance(f, classmethod)):
        return classmethod(mydecorator(f.__func__))
    elif (isinstance(f, staticmethod)):
        return staticmethod(mydecorator(f.__func__))
    elif (isinstance(f, property)):
        return property(mydecorator(f.fget))
    else:
        return decorator.decorator(f)

UPD:抱歉无所事事。在2. *之前的2.7。 ,你应该这样做:

import decorator
def mydecorator(f, *d_args, **d_kwargs):
    if (isinstance(f, classmethod)):
        return classmethod(mydecorator(f.__get__(True).im_func))
    elif (isinstance(f, staticmethod)):
        return staticmethod(mydecorator(f.__get__(True)))
    elif (isinstance(f, property)):
        return property(mydecorator(f.fget))
    else:
        return decorator.decorator(f)

请注意,True语句中的f.__get__(True).im_func个对象可以被除None之外的任何对象替换。

答案 1 :(得分:1)

我把它放回去,这对任何人都有用:

def redecorate(redecorator):
    def wrapper(f):
        info = (f, None)
        if (isinstance(f, classmethod)):
            info = (f.__get__(True).im_func, classmethod)
        elif (isinstance(f, staticmethod)):
            info = (f.__get__(True), staticmethod)
        elif (isinstance(f, property)):
            info = (f.fget, property)

        if (info[1] is not None):
            return info[1](redecorator(info[0]))
        return redecorator(info[0])
    return wrapper

然后,人们会这样使用它:

import decorator
@decorator.decorator
def my_decorator(f, *args, **kwargs):
    print "Pre-process..."
    try:
        return f(*args, **kwargs)
    finally:
        print "Post-process..."

my_redecorator = redecorate(my_decorator)

@my_redecorator
def my_function(a): print "in my_function(a)"

class My_Class(object):
    @my_redecorator
    def my_method(self, a): print "in my_method(self, a)"

    @my_redecorator
    @classmethod
    def my_classmethod1(cls, a): print "in my_classmethod1(cls, a)"

    @classmethod
    @my_redecorator
    def my_classmethod2(cls, b): print "in my_classmethod2(cls, b)"

    @my_redecorator
    @staticmethod
    def my_staticmethod1(a): print "in my_staticmethod1(a)"

    @staticmethod
    @my_redecorator
    def my_staticmethod2(b): print "in my_staticmethod2(b)"

    @my_redecorator
    @property
    def my_property1(self): print "in my_property1(self)"

    @property
    @my_redecorator
    def my_property2(self): print "in my_property2(self)"

现在,如果我打电话给他们:

my_function(1)

My_Class.my_classmethod1(1)
My_Class.my_classmethod2(1)

My_Class.my_staticmethod1(1)
My_Class.my_staticmethod2(2)

my_class = My_Class()

my_class.my_method(1)
my_class.my_property1
my_class.my_property2

输出将是:

Pre-process...
in my_function(a)
Post-process...
Pre-process...
in my_classmethod1(cls, a)
Post-process...
Pre-process...
in my_classmethod2(cls, b)
Post-process...
Pre-process...
in my_staticmethod1(a)
Post-process...
Pre-process...
in my_staticmethod2(b)
Post-process...
Pre-process...
in my_method(self, a)
Post-process...
Pre-process...
in my_property1(self)
Post-process...
Pre-process...
in my_property2(self)
Post-process...

答案 2 :(得分:0)

我这样做的方法是将一个列表_decorated附加到已修饰的函数中,并且能够:

  1. 确定功能是否已装饰
  2. 中的装饰者
  3. 哪个订单。
  4. def mydecorator(f):
        do_decoration()
        if hasattr(f, '_decorated'):
            f._decorated.append(decorator)
        else:
            f._decorated = [decorator]
        return f