有这样的装饰对象
class wait_for_page_load(object):
def __init__(self, driver, time_to_wait=20):
self.driver = driver
self.time_to_wait = time_to_wait
def __call__(self, function):
@functools.wraps(function)
def wrapper(*args):
old_page = self.driver.find_element_by_tag_name('html')
function(*args)
WebDriverWait(self.driver, self.time_to_wait).until(staleness_of(old_page))
return wrapper
我想将它应用于另一个类的方法,如下所示:
class VehiclePage(object):
def __init__(self, driver):
self.driver = driver
@wait_for_page_load(self.driver)
def open(self):
self.driver.get('%s/vehicles/' % BASE_URL)
这给了我一个错误。有没有办法将self.driver
传递给装饰者?
答案 0 :(得分:3)
您不必将self
传递给装饰器对象。如果装饰器返回一个函数,那么该函数将在调用时访问self
。例如
def pass_value(function):
def wrapper(self):
function(self, self.value)
return wrapper
class Printer(object):
def __init__(self, value):
self.value = value
@pass_value
def print_(self, v):
print v
Printer("blah").print_()
此方法的一个问题是它需要self
来实现特定的接口(例如,有一个名为driver
的字段,而不是直接将驱动程序传递给装饰器。)
你的装饰师会变成:
def wait_for_page_load(time_to_wait=20):
def decorator(function):
@functools.wraps(function)
def wrapper(self, *args):
old_page = self.driver.find_element_by_tag_name('html')
function(self, *args)
WebDriverWait(self.driver, time_to_wait).until(staleness_of(old_page))
return wrapper
return decorator
用作:
@wait_for_page_load() # brackets are needed
def open(self):
...
答案 1 :(得分:0)
简答:没有。
答案很长:
实例化类时设置driver
属性。但是,在解释类时会运行装饰器。也就是说,当解释器在加载模块时首先读取它。此时,您还没有准备好任何实例。要做这种事情,你必须重构你的代码。
此外,即使这样可行,您最终也会为所有对象使用装饰器类的单个实例。可能不是你所期望的。
但是,一个简单的解决方法可能是在__init__
中应用装饰器。虽然不是很优雅,但如果您真的需要应用装饰器,那就可以了。
def __init__(self, driver):
self.driver = driver
self.open = wait_for_page_load(self.driver)(self.open)
但是我相信你需要通过调用types来自己将包装器绑定到类.MethodType - 老实说,你可能更好地重新组织你的代码。