2017-03-08 1 views
6

__add__()__radd__()を言って、私はいくつかの魔法のメソッドをサポートして、Fooクラスを含むライブラリーを構築していると言う:pythonで拡張可能な魔法のベストプラクティスはありますか?

>>> class Foo(object): 
...  def __add__(self, rhs): 
...   print("Foo.__add__", rhs) 
...  def __radd__(self, lhs): 
...   print("Foo.__radd__", lhs) 
... 
>>> foo = Foo() 
>>> foo + 3 
Foo.__add__ 3 
>>> 3 + foo 
Foo.__radd__ 3 

3 + fooを計算する場合、Pythonは最初type(3).__add__(3, foo)を呼び出しますが、これはNotImplementedを返すように、それはフォールバックtype(foo).__radd__(foo, 3)へ:

>>> type(3).__add__(3, foo) 
NotImplemented 

私は、開発者は自分のライブラリーの一番上のライブラリを構築できるようにしたいと思い、クラスを含むライブラリを言います、私はそれらを完全に制御してもらいたい。特に、foo + barfoo.__add__(bar)またはbar.__radd__(foo)を呼び出すかどうかを他のライブラリが判断できるようにするメカニズムを実装したいと思います。

NumPyは__array_priority__スキームを使用してこれを解決しました。しかし、これはいくつかの頭痛を引き起こすように思われる(これについて開かれた質問と問題の数を考慮して)。その他のベストプラクティスはありますか?

+1

既存のクラスでも機能しますか? –

+0

あなたの質問はかなり面白いですが、詳細が欠けています。あなたは望ましい行動のより多くの側面をdescrbeできますか? –

答えて

1

一つの人気のオプションは、LHSでサポートされているタイプのリストを維持することであり、RHSのタイプがリストにない場合は、NotImplementedを返す:

class Foo(object): 
    SUPPORTED_TYPES = (int, Foo) 
    def __add__(self, rhs): 
     if isinstance(type(rhs), SUPPORTED_TYPES): 
      [...] # compute self + rhs 
     else: 
      return NotImplemented 

rhsがスマートサブタイプでない限り、これがうまく機能しますSUPPORTED_TYPESのうちの1つ:制御権を得る方法はありません。 さらに、このようにリストを並べ替えることはあまり柔軟性がありません。ハードコードされたタイプのリストよりも、ダックのタイプに頼っているほうが良いでしょう。

1

簡単なオプションは、LHSは、それが(それはRHSのvalue()メソッドを呼び出し、以下の例に)行う必要があるものは何でもできるようにしようとする場合には、それは例外を発生させ、それをキャッチし、NotImplementedを返すことです:

class Foo(object): 
    [...] 
    def __add__(self, rhs): 
     try: 
      return self._value + rhs.value() 
     except AttributeError: 
      return NotImplemented 

シンプルであるため、SUPPORTED_TYPESのリストを維持する必要はありません。しかし、RHSがこのタスクとは何の関係もないvalue()メソッドを実装する危険性があるため、少し危険です。さらに、rhsが結果を完全に制御できる簡単な方法はありません。

Pythonで

、それは許しを請うためにではなく、上記のように、許可を求めるために、通常は良いでしょうが、あなたはrhsvalue()方法があることを確認することを好むことがあります。

class Foo(object): 
    def __add__(self, rhs): 
     rhs_value_func = getattr(rhs, "value", None) 
     if rhs_value_func is None: 
      return NotImplemented 
     else: 
      return self._value + rhs_value_func() 
0

をさらに別のオプションがにありますnumpyのは、その__array_priority__でない多少のように、__foo_priority__ような属性を使用します。

class Foo(object): 
    __foo_priority__ = 0 
    def __add__(self, rhs): 
     delegate = True 
     try: 
      rhs_prio = type(rhs).__foo_priority__ 
      delegate = (self.__foo_priority__ < rhs_prio) 
     except AttributeError: 
      delegate = True 
     if delegate: 
      return NotImplemented 
     else: 
      return self.value_ + rhs.value() 

このオプションは、やや複雑、しかしかなり柔軟です。このオプションの唯一の(マイナーな)問題は、rhsの型に余分な属性を持たせる必要があるため、rhsにこの属性を持たない既存の型を制御する方法はありません。

関連する問題