如何使用代码块装饰实例并访问/使用实例的变量?

问题描述

我尝试为实例(不是类)的方法构建一个装饰器,它可以灵活地将代码块放在方法的前面和/或后面(而不影响其他实例)。直到我下面的代码有效:

def Decorate(func,before = None,after = None): 
    def wrap(*args,**kwargs): 
        if before: before() # code block insert
        result = func(*args,**kwargs) 
        if after: after() # code block insert
        return result 
    return wrap 
  
class test():
    def __init__(self,name):
        self.name = name
    def put(self,prefix):
        print(prefix,self.name)

a = Test('me')

def Before():
    print('before')

def After():
    print('after')

a.put = Decorate(a.put,Before,After)
a.put('it is')

如何扩展访问/使用实例变量和方法代码块?一个代码示例如下所示:

def Before():
    print('before')
    print(self.name)
    self.any_method(any_argument) # just an example!

我已经尝试了几件事情,但都没有成功。而且我已经很难直接在包装器中访问实例值:

def Decorate(func,after = None): 
    def wrap(self,*args,**kwargs): 
        if before: before() # code block insert

        print(self.name) # --> even this DOES NOT WORK!

        result = func(self,**kwargs) 
        if after: after() # code block insert
        return result 
    return wrap 

此处 print(self.name) 抛出错误AttributeError: 'str' object has no attribute 'name'。所以看起来我在下面的代码块之一 (Before() & After()) 中使用相同的注释相去甚远。

补充一点:当我向实例添加方法时,该方法有效: 此方法在类中(因此用于处理字符串和 exec,但可以将名称作为字符串或函数本身传递):

    def addMethod(self,method,givenname = ''):
        print('add')
        if givenname == '': 
            N = method.__name__
        else: 
            N = givenname
        self._methods.append(N)
        exec('self.' + N + ' = ' + method.__name__ + '.__get__(self)')

主体部分的代码如下所示:

def x(self):
    print('hello,',self.name)

a.addMethod(x)
a.x()

感谢任何解决方案,并在此先感谢!

解决方法

from functools import wraps


def Decorate(func,before = None,after = None):
    @wraps(func)
    def wrap(*args,**kwargs): 
        if before: before() # code block insert
        result = func(*args,**kwargs) 
        if after: after() # code block insert
        return result 
    return wrap

def Before():
    print('before')

def After():
    print('after')

class Test():
    def __init__(self,name):
        self.name = name
    def put(self,prefix):
        print(prefix,self.name)
    
    put = Decorate(put,Before,After)

a = Test('me')
a.put("pre")

你可以在你的类中执行你的装饰器。在您的 wrap 中,通过 func 将您获得的任何内容传递给 (*args,**kwargs)self 仍然是 args 中隐含的第一个参数。

编辑:评论中与代码相关的问题


from functools import wraps


def Before(t):
    print('before')
    print(t.name)


def After(t):
    print('after')
    print(t.name)


def Decorate(func,**kwargs): 
        if before: before(args[0]) # code block insert
        result = func(*args,**kwargs) 
        if after: after(args[0]) # code block insert
        return result 
    return wrap

class Test():
    def __init__(self,self.name)

    put = Decorate(put,After)


a = Test('me')
a.put("pre")