【问题标题】:How to decorate an instance with code-blocks and accessing/using the variables of the instance?如何用代码块装饰实例并访问/使用实例的变量?
【发布时间】:2021-04-23 21:00:51
【问题描述】:

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

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, before = None, after = None): 
    def wrap(self, *args, **kwargs): 
        if before: before() # code block insert

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

        result = func(self, *args, **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()

感谢任何解决方案,并提前非常感谢!

【问题讨论】:

    标签: python oop instance decorator wrapper


    【解决方案1】:
    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 中,通过(*args, **kwargs) 将您获得的任何内容传递给funcself 仍然是 args 中隐含的第一个参数。

    编辑:来自 cmets 的代码相关问题


    from functools import wraps
    
    
    def Before(t):
        print('before')
        print(t.name)
    
    
    def After(t):
        print('after')
        print(t.name)
    
    
    def Decorate(func, before = None, after = None):
        @wraps(func)
        def wrap(*args, **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, name):
            self.name = name
        def put(self, prefix):
            print(prefix, self.name)
    
        put = Decorate(put, Before, After)
    
    
    a = Test('me')
    a.put("pre")
    

    【讨论】:

    • 无论如何都可以。问题是,像这样将包括self... 在内的引用添加到before()after() 中:def Before(): print(self.name) 这会导致错误,而我需要这样的方法扩展!
    • @Ulrich 你可以有def Before(t): print(t.name)。您需要将Test 的实例传递给Before。现在,当您调用它时,它需要通过 if before: before(args[0]) 使用该实例
    • 嗨柯,不行不行。我将我当前的代码状态添加到您的答案中。
    • 使用 args[0] 作为实例的函数参数,而不是 *args, **kwargs
    • 不!还是行不通。你能把你的提案作为一个整体粘贴吗?会帮我一个很大的忙!在这一行:if before: before(args[0]) # code block insert 我收到以下错误:AttributeError: 'str' object has no attribute 'name'...
    猜你喜欢
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    相关资源
    最近更新 更多