python中作为装饰器的类方法

问题描述

所以,我正在为 appium 测试编写一个库。 我有一个看起来像这样的主类:

class APP():
    def __init__(self):
        self.variable1 = 1
        self.current_view = "main_screen"

    def do_operation_A(self):
        self.open_side_menu()
        do_something
        self.current_view = "side_menu"
    
    def do_operation_B(self):
        self.open_side_menu()
        do_something_else
        self.current_view = "side_menu"

    def set_landscape(self):
        self.open_settings_menu()
        configure_landscape
        self.current_view = "settings_menu"

这个类有很多操作,所以我可以做 app.do_operation_A() 或 app.set_landscape() 之类的事情,而不必先手动去每个菜单(在类内部解决

为了减少这种情况,如果可能的话,我想实现一个装饰器来做这样的事情:

class APP():
    def __init__(self):
        self.variable1 = 1
        self.current_view = "main_screen"

    #DEFINE_DECORATOR_HERE

    @side_menu
    def do_operation_A(self):
        do_something
    
    @side_menu
    def do_operation_B(self):
        do_something_else

    @settings_menu
    def set_landscape(self):
        configure_landscape

所以我想实现这个装饰器以导航到相应的视图,并更改我用来检查其他函数中某些内容的变量。我看过一些 functools.wraps 的例子,但我不清楚如何在类中实现装饰器来修改这个自变量。

有什么帮助吗?

解决方法

使用装饰器意味着您“包装”了另一个函数,即您调用装饰器,然后从装饰器内部调用该函数。

例如:

import functools

def outer(func):
    @functools.wraps(func)
    def inner(*args,**kwargs):
        return func(*args,**kwargs)
    return inner

定义函数后,将调用装饰器,返回 inner 函数。

无论何时调用 func,实际上都会调用 inner,它运行自己的代码,包括调用原始的 func 函数。

因此对于您的用例,您应该能够创建类似于以下内容的装饰器:

def settings_menu(func):
    @functools.wraps(func)
    def inner(self,*args,**kwargs):
        self.open_settings_menu()
        self.current_view = "settings_menu"
        return func(self,**kwargs)
    return inner
,

所以装饰器基本上是一个返回另一个函数的函数,对吗?

def side_menu(func):
    def wrapper():
        return func()
    
    return wrapper

wrapper 返回的 side_menu 将在调用 App().do_operationA 时被调用。每当调用该方法时,self 始终是第一个参数。或者更确切地说,第一个参数是 App 的实例,但无论如何。所以我们可以这样做:

def side_menu(func):
    def wrapper(self,**kwargs):
        self.open_menu()
        func(self,**kwargs)

    return wrapper

现在,您不希望该方法将自身显示为 wrapper - 您喜欢名称 do_operationA。这就是 @functools.wraps 的用武之地,它使装饰时看起来和工作正常。

def side_menu(func):
    @functools.wraps
    def wrapper(self,**kwargs)

    return wrapper