【问题标题】:Using decorators inside a class在类中使用装饰器
【发布时间】:2017-02-17 06:29:22
【问题描述】:

我正在尝试在我的应用中实现一个简单的日志记录功能。

class messages(object):

    # Implement decorator here
    def on(self):
        def wrapper():
            # Do something here
        return wrapper

    def off(self):
        def wrapper():
            # Do something here
        return wrapper


class website(object):

    @messages.on #This line can be switched on/off
    def login(self):
        # Do a whole bunch of stuff here
        self.response = "[+] Login Succeeded!"

website = website()
website.login() # prints self.response based on @messages.on/off

但我不确定我需要在我的装饰器中应用什么。我曾尝试创建实例并添加参数,但大多会收到 TypeError。我对装饰师相当陌生。任何帮助将不胜感激,我希望下次记住这一点。

【问题讨论】:

  • @Hussain:这在这里并不适用;他们在这里没有使用来自同一类主体的函数。
  • 你的方法没有任何意义。一方面,logger 中的 self 指的是 Utilities 实例,而您没有 - 您的意思是它是 @staticmethod 吗?为什么它在一个类中(这不是 Java)?其次,将其绑定到.sound 属性使其几乎无法重用。为什么不让bark 总是返回'woof',然后让包装器在调用它包装的方法时打印它返回的任何东西?为什么打电话给Dog.bark 时有print?最后,不要使用新实例 Dog 来影响类 Dog;按照惯例,dog = Dog().
  • @MartijnPieters 我打算展示stackoverflow.com/a/1263782/1637867
  • @Hussain:是的,这不适用于这里

标签: python oop decorator


【解决方案1】:
  1. 如果你只想让 Dog 吠叫(如示例中所示),则无需启用装饰器

    class Dog(object):
        def __init__(self):
            self.sound = "Woof!"
    
        def bark(self):
            return self.sound
    
  2. 如果你想为类中的某些函数启用日志记录,这里有一段代码,在 cmets 中有解释

    from functools import wraps
    
    class Utilities(object):
    
        @staticmethod  # no default first argument in logger function
        def logger(f):  # accepts a function
            @wraps(f)  # good practice https://docs.python.org/2/library/functools.html#functools.wraps
            def wrapper(self, *args, **kwargs):  # explicit self, which means this decorator better be used inside classes only
                print("Before:", self.sound)
                result = f(self, *args, **kwargs)
                print("After:", self.sound)
                return result
            return wrapper
    
    
    class Dog(object):
        def __init__(self):
            self.sound = "Woof!"
    
        @Utilities.logger
        def run(self):
            """Perform running movement"""
            print("Running")
    

例子:

>>> dog = Dog()
>>> dog.run()
Before: Woof!
Running
After: Woof!

尽管毕竟没有必要在 Utilities 类中存储装饰器功能 - 最好有一个名为 utils 的单独模块(文件)并将装饰器作为独立函数放在那里

【讨论】:

  • 我想使用这个代码,谢谢,但我不明白它是如何工作的,所以我会做更多的研究。最初,我想在我的代码中的每个方法之后添加 try except 语句,但我想使用装饰器几乎“切换”这个日志记录功能或关闭。我认为装饰器会是一个很好的用例。
  • 我已经更新了代码。谢谢你的帮助。你会推荐同样的建议吗?
  • 装饰器是为多个功能添加相同逻辑的好方法,是的。只需在“之前”和“之后”的位置插入所需的代码。很高兴它对您有用,如果有帮助,您可以将答案标记为已接受:)
【解决方案2】:

以下是您可以使用的示例装饰器:

class Utilities:

    @staticmethod
    def add_logger(func):
        def wrapped_func(*args, **kwargs):
            # Sample logic, feel free to update this
            try:
                func_response = func(*args, **kwargs)
            except:
                print 'I am error handled by logger'
                func_response = None
            return func_response
        return wrapped_func

现在让我们定义你的类:

class Dog(object):

    @Utilities.add_logger 
    def bark(self):
        print 'In bark'

    @Utilities.add_logger 
    def my_error_function(self):
        print 'In my_error_function'
        raise Exception  # <--- Raises Exception

现在,让我们看看它是如何工作的:

>>> dog = Dog()
>>> dog.bark()
In bark
>>> dog.my_error_function()
In my_error_function
I am error handled by logger  # Content from logger in case of exception

注意:你不应该在这里创建一个class 来存储实用函数。创建一个单独的实用程序文件并在那里编写此类函数。

没有类,你的装饰器应该是这样的(比如说在 utility.py 中):

def add_logger(func):
    def wrapped_func(*args, **kwargs):
        # Sample logic, feel free to update this
        try:
            func_response = func(*args, **kwargs)
        except:
            print 'I am error handled by logger'
            func_response = None
        return func_response
    return wrapped_func

要使用它,只需这样做:

import utility

class Dog(object):

    @utility.add_logger
    def bark(self):
        print 'In bark'

【讨论】:

  • 请查看更新后的代码,谢谢。告诉我这是否仍然适用。感谢您的意见!
  • 是的。它是装饰器的骨架。更改 wrapped_func 中的逻辑以实现您想要实现的任何目标
猜你喜欢
  • 1970-01-01
  • 2011-11-20
  • 2021-07-16
  • 2014-01-14
  • 2020-07-22
  • 2019-09-01
  • 2020-01-11
  • 2016-08-18
  • 2020-03-23
相关资源
最近更新 更多