给函数作用域访问调用它的self?

时间:2017-02-22 18:38:20

标签: python oop scope

我有一个“Wrapper”课程。包装器继承自对象,它的主要职责是在测试期间将方法调用挂钩到selenium。它的__init__方法签名是

__init__(self, object_to_wrap, actions={}, **kwargs)

它的一部分功能是将字典作为init方法中的参数,并通过定义object_to_wrap魔术方法将键作为__getattr__对象上的属性公开 (签名:__getattr__(self, item):) 并检查self.actions的{​​{1}}个键。如果找到,则调用该方法。

在测试代码中,初始化看起来类似于:

item

所以,我的问题是,如何使范围或上述方法中的def navigate(scoped_self, to=''): self.driver.switch_to_default_content() self.driver.switch_to.frame(to) scoped_self.navigations.append(to) # the navigate method is scoped in an # instance method of the test class, so it has access to self 成为我的self类的范围,而不是测试类?

为清楚起见,如果找到了我在这个问题中寻找的解决方案,导航实现将变为:

Wrapper

另外为了清楚起见,我很确定我正在寻找的正是Javascripts def navigate(scoped_self, to=''): self.object_to_wrap.switch_to_default_content() self.object_to_wrap.switch_to.frame(to) 所完成的。

UPDATE :在Wrapper类中定义方法(如导航)不是一个选项,因为Wrapper类不能具有特定于测试的逻辑。测试套件在n>上完成。 1个DOM,完全不相关。例如,其中一个测试需要方法“alert_handlers”(覆盖window.alert函数并返回以字符串形式显示的警报),另一个可能需要导航方法,第三个可能需要两者。

更新#2 :感谢下面c17r的回答,我意识到如果没有我的示例中包含的 getattribute 代码,那就好像我在问对于我们已经完成的事情。我正在寻找的是在上面的导航方法中,Function.prototype.bind是Wrapper的实例。

此外,我特意寻找一种“动态”将scoped_self传递给函数的方法(scoped_self“动态”设置Function.prototype.bind的方式this是myEventListener.bind(窗口);如果你不熟悉javascript,请在​​body上创建一个事件监听器,并在{。1}} 没有绑定,然后使用绑定,以查看差异)

此外,我认为在没有我正在寻找的解决方案的情况下提供示例实施可能会有所帮助。目前正在按预期工作:

this

1 个答案:

答案 0 :(得分:0)

如果我理解正确,有3件事:

  1. Wrapper需要将任何未知函数传递给包装项,否则driver.get()将无法正常工作。
  2. navigate函数需要self作为第一个参数,就像在Wrapper
  3. 上实际定义的那样
  4. Wrapper需要将self传递到基于字典的函数中。这有点棘手,因为__getattr__实际上并没有调用函数,所以你需要返回一个正确调用底层函数的函数,类似于装饰器的工作方式。
  5. 像这样:

    class Driver(object):
        def get(self, url):
            print('get')
            print(repr(self))
            print(repr(url))
            print('--')
    
    
    class Wrapper(object):
        def __init__(self, wrapped, actions={}):
            self.wrapped = wrapped
            self.actions = actions
    
        def __getattr__(self, item):            
            if item in self.actions:
                def unwrap(*args, **kwargs):
                    return self.actions[item](self, *args, **kwargs)
                return unwrap
            else:
                return getattr(self.wrapped, item)
    
    
    class Test(object):
        def __init__(self):
            self.driver = Driver();
    
        def spawn_actions(self):
            def navigate(self, to=''):
                print('navigate')
                print(repr(self))
                print(repr(to))
                print(repr(self.wrapped))
                print('--')
    
            return {
                'navigate': navigate
            }
    
        def run(self):
            driver = Wrapper(self.driver, self.spawn_actions())
            driver.get('url')
            driver.navigate('thing')
    

    现在打电话:

    t = Test()
    t.run()
    

    输出:

    get
    <__main__.Driver object at 0x104008630>
    'url'
    --
    navigate
    <__main__.Wrapper object at 0x104008ba8>
    'thing'
    <__main__.Driver object at 0x104008630>
    --
    

    修改

    您还可以将方法动态绑定到实例,而不是__getattr__返回unwrap函数:

    import types
    class Wrapper(object):
        def __init__(self, wrapped, actions={}):
            self.wrapped = wrapped
    
            for name, func in actions.items():
                setattr(self, name, types.MethodType(func, self))
    
        def __getattr__(self, item):
            return getattr(self.wrapped, item)