2017-03-08 48 views
6

说我已经建立了包含Foo类库,支持一些神奇的方法,说__add__()__radd__()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,蟒蛇首先调用type(3).__add__(3, foo),但截至返回NotImplemented,它回落到type(foo).__radd__(foo, 3)

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

我希望开发者能够建立在我的库顶库,说含有类库,我希望他们有完全的控制权。特别是,我想实施一些机制,让其他图书馆可以决定foo + bar是否应拨打foo.__add__(bar)bar.__radd__(foo)

我看到NumPy使用__array_priority__方案解决了这个问题。但是这似乎引起了一些头痛(考虑到有关这个问题的问题和问题的数量)。还有其他的最佳做法吗?

+1

你是否也希望使用现有的类? –

+0

虽然你的问题很有意思,但缺乏细节。你能否描述期望行为的更多方面? –

回答

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

一个简单的选择就是尽量让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

另一个选择是使用这样的属性为__foo_priority__,有点像NumPy的确实与其__array_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进行控制。

相关问题