Reputation: 383
So, im writing a library for appium tests. I have a main class that look like this:
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"
The class has a lot of operations so i can do things like app.do_operation_A() or app.set_landscape() without having to first go to each menu manually (resolved inside the class)
To reduce this i want to implement a decorator to do something like this if possible:
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
So i want to implement this decorators to navigate to the corresponding view and also change that variable that i use to check some things in other functions. I have seen some examples with functools.wraps but is not clear to me of how to implement the decorator inside the class to be able to modify this self variables.
Any help?
Upvotes: 2
Views: 4354
Reputation: 66
Using a decorator means that you "wrap" your other function, i.e. you call the decorator and then call the function from inside the decorator.
E.g.:
import functools
def outer(func):
@functools.wraps(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
Upon defining the function, the decorator will be called, returning the inner
function.
Whenever you call func
, you will in reality call inner
, which runs it's own code, including calling the original func
function.
So for your use case, you should be able to create decorators similar to:
def settings_menu(func):
@functools.wraps(func)
def inner(self, *args, **kwargs):
self.open_settings_menu()
self.current_view = "settings_menu"
return func(self, *args, **kwargs)
return inner
Upvotes: 4
Reputation: 675
So a decorator is basically a function that returns another function, right?
def side_menu(func):
def wrapper():
return func()
return wrapper
The wrapper
, returned by side_menu
, will be called whenever App().do_operationA
is called. And whenever that method is called, self
is always the first argument. Or rather, the first argument is the instance of App, but whatever. So we could do:
def side_menu(func):
def wrapper(self, *args, **kwargs):
self.open_menu()
func(self, *args, **kwargs)
return wrapper
Now, you don't want the method to present itself as wrapper
- you like the name do_operationA
. That's where @functools.wraps
comes in, it makes things look and work right when decorating.
def side_menu(func):
@functools.wraps
def wrapper(self, *args, **kwargs):
self.open_menu()
func(self, *args, **kwargs)
return wrapper
Upvotes: 2