有没有办法在 Python 中获得临时多态性?

Is there a way to get ad-hoc polymorphism in Python?

许多语言开箱即用地支持 ad-hoc polymorphism(a.k.a。函数重载)。但是,Python 似乎选择退出。尽管如此,我可以想象在 Python 中可能会有一个技巧或一个库能够实现它。有人知道这样的工具吗?

例如,在 Haskell 中,可以使用它来生成不同类型的测试数据:

-- In some testing library:
class Randomizable a where
   genRandom :: a

-- Overload for different types
instance Randomizable String where genRandom = ...
instance Randomizable Int    where genRandom = ...
instance Randomizable Bool   where genRandom = ...


-- In some client project, we might have a custom type:
instance Randomizable VeryCustomType where genRandom = ...

这样做的好处是我可以在不接触测试库的情况下为自己的自定义类型扩展 genRandom

你如何在 Python 中实现这样的目标?

这是否算作 ad hock 多态性?

class A:
    def __init__(self):
        pass

    def aFunc(self):
        print "In A"

class B:
    def __init__(self):
        pass

    def aFunc(self):
        print "In B"

f = A()
f.aFunc()
f = B()
f.aFunc()

输出

In A
In B

Python 不是一种强类型语言,所以你是否拥有 Randomizable 的实例或其他具有相同方法的 class 的实例并不重要。

获得所需外观的一种方法可能是:

types_ = {}
def registerType ( dtype , cls ) :
    types_[dtype] = cls
def RandomizableT ( dtype ) :
    return types_[dtype]

首先,是的,我确实用大写字母定义了一个函数,但它更像是一个 class。例如:

registerType ( int , TheLibrary.Randomizable )
registerType ( str , MyLibrary.MyStringRandomizable )

然后,稍后:

type = ... # get whatever type you want to randomize
randomizer = RandomizableT(type) ()
print randomizer.getRandom()

多态的另一个版本

from module import aName

如果两个模块使用相同的接口,您可以导入其中一个并在您的代码中使用它。 例如 from xml.etree.ElementTree import XMLParser

Python 函数无法根据静态编译时类型自动特化。因此,它的结果只能取决于它在 运行 时间和全局(或本地)环境中收到的参数,除非函数本身是可就地修改的并且可以携带一些状态。

您的通用函数 genRandom 除了输入信息外不接受任何参数。因此在 Python 中它至少应该接收类型作为参数。由于无法修改内置 类,因此此类 类 的通用函数(实例)实现应以某种方式通过全局环境提供或包含在函数本身中。

我发现从 Python 3.4 开始,有 @functools.singledispatch decorator. However, it works only for functions which receive a type instance (object) as the first argument, so it is not clear how it could be applied in your example. I am also a bit confused by its rationale:

In addition, it is currently a common anti-pattern for Python code to inspect the types of received arguments, in order to decide what to do with the objects.

我知道 anti-pattern 是一个行话术语,指的是一种被认为是不受欢迎的模式(并且根本不意味着没有模式)。因此,基本原理声称检查参数类型是不可取的,并且该声明用于证明引入一种工具可以简化......对参数类型的调度。 (顺便注意,根据PEP 20,"Explicit is better than implicit.")

Guido van Rossum 于 2005 年发表的 "Alternative approaches" section of PEP 443 "Single-dispatch generic functions" however seems worth reading. There are several references to possible solutions, including one to "Five-minute Multimethods in Python" 文章。