2016-05-07 18 views
0

セレンのフレームのイン/アウト操作をラッピングするために、Pythonクラスの内部で内部デコレータを作成したいと考えています。 Pythonクラスの内部デコレータ

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つのパラメータを期待したが、それは自己について何も知らないデコレータコンテキストにされ、だから私は定義しなければならないと内側の関数 'framed_function'のソリューションをより少なくエレガント:

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

の提案?

答えて

2

クラスのメソッドを定義するとき、クラスオブジェクトはまだありません。確かにそのクラスのインスタンスは存在しないので、selfにバインドされるものはありません。です。その代わりに、メソッドはインスタンスオブジェクトにルックアップされた時点でインスタンスにバインドされます。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_function()を飾るために使用されているので、framed()戻りdecorator()、。そうするとwrapper()が返され、実際に生成されたMyPageクラスオブジェクトに追加されます。 MyPage()のインスタンスの場合、instance.framed_function()にアクセスすると、wrapper()がそのインスタンスにバインドされるので、selfは、instanceオブジェクトにバインドされます。 wrapperの範囲内では、インスタンスself、および元のfunctionオブジェクト(バインドされていない)およびframe_query文字列にアクセスできます。

+0

デコレータがオブジェクトインスタンスにどのように追加されているのかわからないときは間違いがありますが、私はこのことを理解するために参考にしています。 – gerosalesc

関連する問題