【问题标题】:Inner decorators in Python classPython 类中的内部装饰器
【发布时间】:2016-09-02 15:20:55
【问题描述】:

我想在我的 Python 类中使用它创建一个内部装饰器,用于包装 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()

建议?

【问题讨论】:

    标签: python python-3.x oop decorator python-decorators


    【解决方案1】:

    为类定义方法时,还没有类对象。当然还没有那个类的实例,所以self 没有任何东西被绑定到either。相反,方法在实例对象上查找时绑定到实例,请参阅Python descriptor HOWTO。只需从您的装饰器返回一个新的函数对象,该对象将被绑定。

    另外,Python 没有隐私模型,因此也没有“内部”的概念(对于类或方法或任何东西)。只需将您的装饰器放在类之外,这样可以更轻松地维护和重用,并避免污染您的类 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()返回decorator(),然后又用来装饰framed_function();这样做会返回wrapper(),它被添加到实际生成的MyPage 类对象中。然后在MyPage() 的实例上,访问instance.framed_function() 会将wrapper() 绑定到该实例,以便self 绑定到该instance 对象。在wrapper 中,您可以以self 的身份访问实例,以及原始function 对象(未绑定)和frame_query 字符串。

    【讨论】:

    • 有效,但是当您不知道如何将装饰器添加到对象实例时肯定会很棘手(我的失败),我将看看您引用的这篇阅读文章以了解更多信息。
    猜你喜欢
    • 1970-01-01
    • 2021-10-04
    • 2019-09-20
    • 2010-10-14
    • 2017-08-01
    • 2011-04-28
    • 1970-01-01
    • 2012-02-09
    相关资源
    最近更新 更多