在python中是否有可扩展魔术方法的最佳实践?

Min*_*ark 6 python magic-methods

说我已经建立包含一个库Foo类,与一些魔术方法的支持,说__add__()__radd__():

>>> 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
Run Code Online (Sandbox Code Playgroud)

在计算时3 + foo,python首先调用type(3).__add__(3, foo),但是当它返回时NotImplemented,它会回退到type(foo).__radd__(foo, 3):

>>> type(3).__add__(3, foo)
NotImplemented
Run Code Online (Sandbox Code Playgroud)

我希望开发人员能够在我的库之上构建库,比如一个包含类的库Bar,我希望它们能够完全控制.特别是,我想实现一些机制,让其他库决定是否foo + bar应该调用foo.__add__(bar)bar.__radd__(foo).

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

Min*_*ark 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
Run Code Online (Sandbox Code Playgroud)

这很有效,除非rhs它是其中之一的智能子类型SUPPORTED_TYPES:它无法获得控制。而且,这种方式列出类型不是很灵活。依赖鸭子类型可能比依赖硬编码类型列表更好。