Python class 中的内部装饰器

Inner decorators in Python class

我想在我的 Python class 中使用它创建一个内部装饰器来包装 selenium 框架切换进出操作。所以我尝试了这个:

class MyPage(object):
    # ...
    def framed(self, frame_query: str):
        def decorator(function):
            @functools.wraps(function)
            def wrapper(*args, **kwargs):
                frame = self.driver.find_element(By.XPATH, frame_query)
                self.driver.switch_to.frame(frame)
                out = function(*args, **kwargs)
                self.driver.switch_to.default_content()
                return out
            return wrapper
        return decorator
    # ...
    @framed('//myxpath/iframe')
    def framed_function(self):
        # ...

但是我收到这个错误:

TypeError: framed() missing 1 required positional argument: 'frame_query'

显然它需要 2 个参数,包括 self 但在装饰器上下文中它对 self 一无所知,所以我不得不在 ´framed_function´ 中定义和内部函数使解决方案很多不太优雅:

# My workaround
def framed_function(self):
    @framed('//myxpath/iframe')
    def actual_framed():
        #...
    actual_framed()

建议?

在为 class 定义方法时,还没有 class 对象。当然还没有 class 的实例,所以 self 没有任何东西可以绑定到 或者 。相反,方法在实例对象上查找时绑定到实例,请参阅 Python descriptor HOWTO。只是 return 来自装饰器的新函数对象将被绑定。

此外,Python 没有隐私模型,因此也没有 'inner' 的概念(对于 classes 或方法或任何东西)。只需将你的装饰器放在 class 之外,这样更易​​于维护和重用,并避免污染你的 class API.

这意味着您的 wrapped() 函数将成为一个方法,并且在绑定时将传递给 self 参数。使用它,并将其显式传递给包装的函数对象(因为该函数未绑定):

def framed(frame_query: str):
    def decorator(function):
        @functools.wraps(function)
        def wrapper(self, *args, **kwargs):
            frame = self.driver.find_element(By.XPATH, frame_query)
            self.driver.switch_to.frame(frame)
            out = function(self, *args, **kwargs)
            self.driver.switch_to.default_content()
            return out
        return wrapper
    return decorator

class MyPage(object):
    @framed('//myxpath/iframe')
    def framed_function(self):

所以framed()returnsdecorator(),进而用来修饰framed_function();这样做 returns wrapper(),它被添加到实际生成的 MyPage class 对象中。然后,在 MyPage() 的实例上,访问 instance.framed_function() 会将 wrapper() 绑定到该实例,因此 self 将绑定到该 instance 对象。在 wrapper 中,您可以作为 self 访问实例,以及原始 function 对象(未绑定)和 frame_query 字符串。