【问题标题】:Decorating a method - how to call the method in oo fashion instead of procedural fashion装饰方法 - 如何以 oo 方式而不是程序方式调用方法
【发布时间】:2012-07-30 13:18:05
【问题描述】:

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

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()

【问题讨论】:

  • 请修正您的格式。看起来并非所有代码都进入了代码块。
  • ... 现在的情况有什么问题?装饰器应用于函数,它们不关心类,编写类时也不应该关心。 (另外,如果你保持现在的样子,你的代码可以在课堂外使用)

标签: python oop decorator


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    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()
    

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

    【讨论】:

      猜你喜欢
      • 2017-05-25
      • 1970-01-01
      • 1970-01-01
      • 2016-01-03
      • 2019-04-01
      • 2016-06-11
      • 2010-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多