【问题标题】:Pass self to decorator object将 self 传递给装饰器对象
【发布时间】:2015-12-13 07:49:07
【问题描述】:

拥有这样的装饰器对象

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 传递给装饰器?

【问题讨论】:

  • 你能把它给你的错误贴出来吗?
  • name 'self' 未定义

标签: python decorator python-2.x python-decorators


【解决方案1】:

您不必将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):
    ...

【讨论】:

    【解决方案2】:

    简答:不,没有。

    长答案: driver 属性在您实例化类时设置。但是,在解释类时会运行装饰器。也就是说,当解释器在加载模块时第一次读取它时。此时,您还没有准备好任何实例。要执行此类操作,您必须重构代码。

    此外,即使这样可行,您最终也会为所有对象使用装饰器类的单个实例。可能不是你所期望的。

    不过,一个简单的解决方法是在__init__ 中应用装饰器。虽然不是很优雅,但如果您真的需要应用装饰器,这将是可行的。

    def __init__(self, driver):
        self.driver = driver
        self.open = wait_for_page_load(self.driver)(self.open)
    

    但是我相信您需要自己通过调用 types.MethodType 将包装器绑定到类 - 老实说,您最好重新组织代码。

    【讨论】:

      猜你喜欢
      • 2021-12-23
      • 2021-02-11
      • 2018-12-02
      • 1970-01-01
      • 2021-11-15
      • 2014-11-17
      • 1970-01-01
      • 2021-11-21
      相关资源
      最近更新 更多