代码之家  ›  专栏  ›  技术社区  ›  Silly Freak

修饰方法时访问绑定方法或self

  •  3
  • Silly Freak  · 技术社区  · 6 年前

    def decorator(func):
        def enhanced(*args, **kwargs):
            func(*args, **kwargs)
    
        func.enhanced = enhanced
        return func
    
    @decorator
    def function():
        pass
    
    class X:
        @decorator
        def function(self):
            pass
    
    x = X()
    
    function()
    function.enhanced()
    x.function()
    # x.function.enhanced()
    x.function.enhanced(x)
    

    前三个电话工作正常,但是 x.function.enhanced() 没有;我得写信 x.function.enhanced(x) 让它工作。我知道这是因为 func 传递给decorator的不是绑定方法而是函数,因此需要传递 self

    但我怎么才能避开这个?从我对描述符的一点点了解来看,它们只在查找类时才相关,而且 功能 不是一门课, func.enhanced

    有什么我能做的吗?

    2 回复  |  直到 6 年前
        1
  •  4
  •   blhsing    6 年前

    您可以返回 descriptor enhanced 属性映射到 包装函数:

    from functools import partial
    def decorator(func):
        class EnhancedProperty:
            # this allows function.enhanced() to work
            def enhanced(self, *args, **kwargs):
                print('enhanced', end=' ') # this output is for the demo below only
                return func(*args, **kwargs)
            # this allows function() to work
            def __call__(self, *args, **kwargs):
                return func(*args, **kwargs)
            def __get__(self, obj, objtype):
                class Enhanced:
                    # this allows x.function() to work
                    __call__ = partial(func, obj)
                    # this allows x.function.enhanced() to work
                    enhanced = partial(self.enhanced, obj)
                return Enhanced()
        return EnhancedProperty()
    

    @decorator
    def function():
        print('function')
    
    class X:
        @decorator
        def function(self):
            print('method of %s' % self.__class__.__name__)
    
    x = X()
    
    function()
    function.enhanced()
    x.function()
    x.function.enhanced()
    

    将输出:

    function
    enhanced function
    method of X
    enhanced method of X
    
        2
  •  3
  •   juanpa.arrivillaga    6 年前

    正如我在@blhsing对答案的评论中所说的一个例子:

    class EnhancedProperty:
        def __init__(self, func):
            self.func = func
        def enhanced(self, *args, **kwargs):
            return self.func(*args, **kwargs)
        def __call__(self, *args, **kwargs):
            return self.func(*args, **kwargs)
        def __get__(self, obj, typ):
            return Enhanced(self.func, obj, typ)
    
    class Enhanced:
        def __init__(self, func, obj, typ):
            self.func = func
            self.obj = obj
            self.typ = typ
        def __call__(self, *args, **kwargs):
            return self.func.__get__(self.obj, self.typ)(*args, **kwargs)
        def enhanced(self, *args, **kwargs):
            return self.func(self.obj, *args, **kwargs)
    
    def decorator(f):
        return EnhancedProperty(f)
    

    在REPL中:

    In [2]: foo(8, -8)
    Out[2]: 1040
    
    In [3]: foo.enhanced(8, -8)
    Out[3]: 1040
    
    In [4]: Bar().baz('foo')
    Out[4]: ('foo', 'foo')
    
    In [5]: Bar().baz.enhanced('foo')
    Out[5]: ('foo', 'foo')