有没有办法在Python中获得ad-hoc多态?

时间:2015-10-16 18:32:19

标签: python types polymorphism adhoc-polymorphism

许多语言开箱即用支持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中实现这样的目标?

4 个答案:

答案 0 :(得分:3)

Python不是一种强类型语言,所以如果你有一个Randomizable实例或者其他一些具有相同方法的实例,那真的没关系。

获得您想要的外观的一种方法是:

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

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

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

然后,后来:

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

答案 1 :(得分:1)

Python函数不能基于静态编译时类型自动进行专门化。因此,除非函数本身可以就地修改并且可以携带某些状态,否则它的结果只能取决于在运行时以及在全局(或局部)环境中接收到的参数。

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

我发现自Python 3.4起,就有@functools.singledispatch装饰器。但是,它仅适用于将类型实例(对象)作为第一个参数的函数,因此,尚不清楚如何将其应用于示例中。我也对其rationale感到困惑:

  

此外,当前流行的Python代码反模式是检查接收到的参数的类型,以便决定如何处理对象。

我了解到 anti-pattern 是图案的行话,被认为是不受欢迎的(而且并不意味着没有图案)。因此,基本原理要求检查参数类型是不希望的,并且此要求用于证明引入一种可以简化参数类型调度的工具是合理的。 (顺便说一下,请注意,根据PEP 20,“显式优于隐式。”)

"Alternative approaches"PEP 443 "Single-dispatch generic functions"部分似乎值得阅读。可能的解决方案有多种参考,其中包括Guido van Rossum在2005年发表的"Five-minute Multimethods in Python"一文。

答案 2 :(得分:0)

这是否适用于广告素材多态性?

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

答案 3 :(得分:0)

多态的另一个版本

from module import aName

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