Python 在 class 中修饰一个方法并继承
Python decorating a method in a class and inheritance
我正在为 GUI 应用程序编写测试自动化框架,我想使用装饰器来捕获由 class(例如登录)中的方法生成的弹出窗口
我有一个 _BaseWindow
class 跟踪每个 window 中的 GUI 元素(例如:菜单栏、弹出窗口),它由MainWindow
class。 MainWindow
class 跟踪主菜单上的按钮,以及单击其中一个按钮时生成的对话框。例如,如果您单击主菜单上的登录按钮,将加载登录对话框。
class _BaseWindow(object):
def __init__(self):
self.window = "windowName"
self.popup = None
def _catch_popups(self, method):
from functools import wraps
@wraps(method)
def wrapper(*args, **kwargs):
# get a list of the open windows before the method is run
before = getwindowlist()
retval = method(*args, **kwargs)
# get a list of the open windows after the method is run
after = getwindowlist()
for window in after:
if window not in before:
self.popup = window
break
return retval
return wrapper
class MainWindow(_BaseWindow):
def __init__(self):
self.dialog = None
self.logged_in = False
# buttons
self.login_button = "btnLogin"
super(MainWindow, self).__init__()
def click_login(self):
if not self.dialog:
mouseclick(self.window, self.login_button)
self.dialog = LoginDialog()
class LoginDialog(_BaseWindow):
def __init__(self):
# buttons
self.button_ok = "btnLoginOK"
self.button_cancel = "btnLoginCancel"
# text input
self.input_username = "txtLoginUsername"
self.input_password = "txtLoginPassword"
super(LoginDialog, self).__init__()
@MainWindow._catch_popups
def perform_login(self, username, password):
input_text(self.input_username, username)
input_text(self.input_password, password)
mouseclick(self.window, self.button_ok)
当我尝试对此进行测试时,我得到:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "objects/gui.py", line 185, in <module>
class LoginDialog(_BaseWindow):
File "objects/gui.py", line 236, in LoginDialog
@MainWindow._catch_popups
TypeError: unbound method _catch_popups() must be called with
MainWindow instance as first argument (got function instance instead)
当我尝试将 MainWindow instance
指定为:
@MainWindow._catch_popups(self)
我得到:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "objects/gui.py", line 185, in <module>
class LoginDialog(_BaseWindow):
File "objects/gui.py", line 236, in LoginDialog
@MainWindow._catch_popups(self)
NameError: name 'self' is not defined
如果能帮助理解这一点,我们将不胜感激。
您的结构有误。 class 主体中定义的实例方法与 class 同时创建,因此是未绑定方法。因此,在创建时,没有 self
可供参考。您的 _catch_popups
方法需要一个实例。
自然的解决方案是将 _catch_popups
更改为 staticmethod
returns 实例方法。
@staticmethod
def _catch_popups(method):
from functools import wraps
@wraps(method)
def wrapper(self, *args, **kwargs):
before = getwindowlist()
retval = method(self, *args, **kwargs) # notice that self is passed
after = getwindowlist()
try: self.popup = next(w for w in after if w not in before)
return retval
return wrapper
这里,self
被显式传递给了method
,因为它在传递给装饰器时仍然是未绑定的实例方法。
正如您评论中所建议的那样,您想将弹出窗口添加到 window 实例。为此,您可以更新以下方法:
def click_login(self):
if not self.dialog:
mouseclick(self.window, self.login_button)
self.dialog = LoginDialog(self) # pass window to dialog __init__
class LoginDialog(_BaseWindow):
def __init__(self, parent_window):
# original code
self.parent = parent_window
@staticmethod
def _catch_popups(method):
def wrapper(self, *args, **kwargs):
# original code
try: self.parent.popup = ... # add to parent rather than self
return retval
return wrapper
我正在为 GUI 应用程序编写测试自动化框架,我想使用装饰器来捕获由 class(例如登录)中的方法生成的弹出窗口
我有一个 _BaseWindow
class 跟踪每个 window 中的 GUI 元素(例如:菜单栏、弹出窗口),它由MainWindow
class。 MainWindow
class 跟踪主菜单上的按钮,以及单击其中一个按钮时生成的对话框。例如,如果您单击主菜单上的登录按钮,将加载登录对话框。
class _BaseWindow(object):
def __init__(self):
self.window = "windowName"
self.popup = None
def _catch_popups(self, method):
from functools import wraps
@wraps(method)
def wrapper(*args, **kwargs):
# get a list of the open windows before the method is run
before = getwindowlist()
retval = method(*args, **kwargs)
# get a list of the open windows after the method is run
after = getwindowlist()
for window in after:
if window not in before:
self.popup = window
break
return retval
return wrapper
class MainWindow(_BaseWindow):
def __init__(self):
self.dialog = None
self.logged_in = False
# buttons
self.login_button = "btnLogin"
super(MainWindow, self).__init__()
def click_login(self):
if not self.dialog:
mouseclick(self.window, self.login_button)
self.dialog = LoginDialog()
class LoginDialog(_BaseWindow):
def __init__(self):
# buttons
self.button_ok = "btnLoginOK"
self.button_cancel = "btnLoginCancel"
# text input
self.input_username = "txtLoginUsername"
self.input_password = "txtLoginPassword"
super(LoginDialog, self).__init__()
@MainWindow._catch_popups
def perform_login(self, username, password):
input_text(self.input_username, username)
input_text(self.input_password, password)
mouseclick(self.window, self.button_ok)
当我尝试对此进行测试时,我得到:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "objects/gui.py", line 185, in <module>
class LoginDialog(_BaseWindow):
File "objects/gui.py", line 236, in LoginDialog
@MainWindow._catch_popups
TypeError: unbound method _catch_popups() must be called with
MainWindow instance as first argument (got function instance instead)
当我尝试将 MainWindow instance
指定为:
@MainWindow._catch_popups(self)
我得到:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "objects/gui.py", line 185, in <module>
class LoginDialog(_BaseWindow):
File "objects/gui.py", line 236, in LoginDialog
@MainWindow._catch_popups(self)
NameError: name 'self' is not defined
如果能帮助理解这一点,我们将不胜感激。
您的结构有误。 class 主体中定义的实例方法与 class 同时创建,因此是未绑定方法。因此,在创建时,没有 self
可供参考。您的 _catch_popups
方法需要一个实例。
自然的解决方案是将 _catch_popups
更改为 staticmethod
returns 实例方法。
@staticmethod
def _catch_popups(method):
from functools import wraps
@wraps(method)
def wrapper(self, *args, **kwargs):
before = getwindowlist()
retval = method(self, *args, **kwargs) # notice that self is passed
after = getwindowlist()
try: self.popup = next(w for w in after if w not in before)
return retval
return wrapper
这里,self
被显式传递给了method
,因为它在传递给装饰器时仍然是未绑定的实例方法。
正如您评论中所建议的那样,您想将弹出窗口添加到 window 实例。为此,您可以更新以下方法:
def click_login(self):
if not self.dialog:
mouseclick(self.window, self.login_button)
self.dialog = LoginDialog(self) # pass window to dialog __init__
class LoginDialog(_BaseWindow):
def __init__(self, parent_window):
# original code
self.parent = parent_window
@staticmethod
def _catch_popups(method):
def wrapper(self, *args, **kwargs):
# original code
try: self.parent.popup = ... # add to parent rather than self
return retval
return wrapper