0

跟进一个较早的线程,我的问题是如何使用这个表达式:fn(self,*args, **kwargs并像这样以 oo 方式调用它这self.fn(...)是我的总程序,其中失败的行被注释掉:

def formatHeader(fn):
    def wrapped(*args, **kwargs):
        print "here is args prior to extraction - {0}".format(args)
        if len(args) > 1:
            self,args = args  # remove self from args
        else:
            self, args= args[0], ()
        print("Here are the arguments after extraction: {0} {1}".format(self, args))
        #return '<div class="page_header">' + self.fn(*args, **kwargs)+'</div>'
        return '<div class="page_header">' + fn(self,*args, **kwargs)+'</div>'
    return wrapped    

class MyPage(object):
    def __init__(self):
        self.PageName = ''

    def createPage(self):
        pageHeader = self.createHeader()
        return pageHeader

    def addem(self, a, b):
        return a + b

    @formatHeader   #<----- decorator
    def createHeader(self):
        return "Page Header " + self.PageName


obj = MyPage()

print obj.createHeader()
4

2 回答 2

3

首先,self不存在于该范围内。 self是一个标签,按照惯例,它指的是类的实例方法中的当前实例。其次,装饰器并不意味着知道它们正在包装的函数的实例(至少在默认情况下)。该方法绑定到实例,并且装饰器对作为可调用黑盒传递的绑定方法进行操作。如果你想从装饰器中访问实例成员(你不应该这样做,因为这实际上破坏了oo),你必须将实例传递给装饰器,这意味着将装饰器封闭在进一步的闭包中,或使用自省从装饰器代码中动态发现拥有的实例。

于 2012-08-01T15:44:05.743 回答
1

问题是您的包装器想要访问它所应用到的实例的另一个方法,但它直到运行时才被传递——与装饰器运行时的类定义时间相反)。基本上你需要一个特定于实例的方法装饰器。您可以通过使用PythonDecoratorLibrary中的实例配方使装饰器成为类方法装饰器中描述的描述符来完成此操作。

以下是将它应用于您的示例代码(进行了一些外观更改):

from functools import wraps

def formatHeader(fn):

    class Descriptor(object):
        def __init__(self, fn):
            self.fn = fn

        def __get__(self, instance, klass):
            if instance is None:  # Class method was requested
                return self.make_unbound(klass) #  will raise TypeError
            return self.make_bound(instance)

        def make_unbound(self, klass):
            @wraps(self.fn)
            def wrapped(*args, **kwargs):
                '''This documentation will vanish :)'''
                raise TypeError(
                    'unbound method {}() must be called with {} instance '
                    'as first argument (got nothing instead)'.format(
                        self.fn.__name__, klass.__name__)
                )
            return wrapped

        def make_bound(self, instance):
            @wraps(self.fn)
            def wrapped(*args, **kwargs):
                '''This documentation will disapear :)'''
                return ('<div class="page_header">' +
                        self.fn(instance, *args, **kwargs) + '</div>')

            # This instance does not need the descriptor anymore,
            # let it find the wrapped method directly next time:
            setattr(instance, self.fn.__name__, wrapped)
            return wrapped

    return Descriptor(fn)

class MyPage(object):
    def __init__(self):
        self.PageName = ''

    def createPage(self):
        pageHeader = self.createHeader()
        return pageHeader

    def addem(self, a, b):
        return a + b

    @formatHeader   #<----- decorator
    def createHeader(self):
        return "Page Header " + self.PageName


obj = MyPage()

print obj.createHeader()

请注意,self嵌套 Descriptor 类方法中的参数是指 Descriptor 类的一个实例,而不是其方法被包装的类(instance在代码中)。

于 2012-08-01T19:26:58.147 回答