Python的最佳维护通用函数实现是什么?

时间:2009-09-18 14:54:28

标签: python generics

根据其所有参数的类型调度generic function。程序员定义了函数的几种实现。在呼叫时根据其参数的类型选择正确的一个。这对于对象适应等很有用。 Python有一些通用函数,包括len()

这些软件包倾向于允许代码如下所示:

@when(int)
def dumbexample(a):
    return a * 2

@when(list)
def dumbexample(a):
    return [("%s" % i) for i in a]

dumbexample(1) # calls first implementation
dumbexample([1,2,3]) # calls second implementation

我最近一直在考虑的一个不那么愚蠢的例子是需要用户的Web组件。集成商不需要特定的Web框架,只需编写类似的内容:

class WebComponentUserAdapter(object):
    def __init__(self, guest):
        self.guest = guest
    def canDoSomething(self):
        return guest.member_of("something_group")

@when(my.webframework.User)
componentNeedsAUser(user):
    return WebComponentUserAdapter(user)

Python有一些通用的函数实现。为什么我会选择其中一个呢?如何在应用程序中使用该实现?

我熟悉Zope的zope.component.queryAdapter(object, ISomething)。程序员注册一个可调用的适配器,该适配器将特定类的对象作为其参数,并返回与接口兼容的东西。这是允许插件的有用方法。与猴子修补不同,即使对象需要使用相同的方法名称来适应多个接口,它也能工作。

3 个答案:

答案 0 :(得分:7)

我推荐P. Eby的PEAK-Rules库。同一作者(虽然已弃用)是RuleDispatch包(PEAK-Rules的前身)。后者不再维持IIRC。

PEAK-Rules有许多不错的功能,其中之一就是(很好,不容易,但是)可扩展。除了类型ony的“经典”调度之外,它还将任意表达式的调度称为“监护人”。

len()函数不是真正的泛型函数(至少在上面提到的包的意义上,从某种意义上说,这个术语在Common Lisp,{{3}等语言中使用}或Dylan),因为它只是一个方便的语法,用于调用特殊命名(但其他常规)方法:

len(s) == s.__len__()

另请注意,这只是单一调度,即实际接收器(上面代码中的s)确定调用的方法实现。甚至是一个假设的

def call_special(receiver, *args, **keys):
    return receiver.__call_special__(*args, **keys)

仍然是单调度函数,因为在解析要调用的方法时仅使用接收器。其余的参数只是传递,但它们不会影响方法选择。

这与multi-dispatch不同,后者没有专用接收器,并且所有参数都用于查找要调用的实际方法实现。这就是实际上使整个事情变得有价值的东西。如果它只是一些奇怪的语法糖,没有人会打扰使用它,恕我直言。

from peak.rules import abstract, when

@abstract
def serialize_object(object, target):
    pass

@when(serialize_object, (MyStuff, BinaryStream))
def serialize_object(object, target):
    target.writeUInt32(object.identifier)
    target.writeString(object.payload)

@when(serialize_object, (MyStuff, XMLStream))
def serialize_object(object, target):
    target.openElement("my-stuff")
    target.writeAttribute("id", str(object.identifier))
    target.writeText(object.payload)
    target.closeElement()

在此示例中,调用

serialize_object(MyStuff(10, "hello world"), XMLStream())

考虑两个参数,以决定实际调用哪个方法。

对于Python中泛型函数的一个很好的使用场景,我建议阅读Cecil的重构代码,它为使用泛型函数(使用RuleDispatch)访问权限检查提供了一个非常优雅的解决方案。

答案 1 :(得分:0)

你可以使用这样的结构:

def my_func(*args, **kwargs):
    pass

在这种情况下,args将是任何未命名参数的列表,kwargs将是已命名参数的字典。从这里,您可以检测其类型并采取适当的行动。

答案 2 :(得分:0)

我无法看到这些“通用”功能的重点。这听起来像是简单的多态性。

您可以像这样实现“通用”功能,而无需使用任何运行时类型标识。

class intWithDumbExample( int ):
    def dumbexample( self ):
        return self*2

class listWithDumbExmaple( list ):
    def dumpexample( self ):
        return [("%s" % i) for i in self]

def dumbexample( a ):
    return a.dumbexample()