一个通用的功能是基于其所有参数的类型出动.程序员定义了函数的几种实现.在调用时根据其参数的类型选择正确的一个.这对于对象适应等很有用.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
Run Code Online (Sandbox Code Playgroud)
我最近一直在考虑的一个不那么愚蠢的例子是需要用户的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)
Run Code Online (Sandbox Code Playgroud)
Python有一些通用的函数实现.为什么我会选择其中一个呢?如何在应用程序中使用该实现?
我对Zope很熟悉zope.component.queryAdapter(object, ISomething).程序员注册一个可调用的适配器,该适配器将特定类的对象作为其参数,并返回与接口兼容的东西.这是允许插件的有用方法.与猴子修补不同,即使对象需要使用相同的方法名称来适应多个接口,它也能工作.
我推荐P. Eby 的PEAK规则库.同一作者(虽然已弃用)是RuleDispatch包(PEAK-Rules的前身).后者不再维持IIRC.
PEAK-Rules有许多不错的功能,其中之一就是(好,不容易,但是)可扩展.除了onty类型的"经典"调度之外,它还将任意表达式的调度称为"监护人".
该len()函数不是一个真正的泛型函数(至少在上面提到的包的意义上,在某种意义上,这个术语在Common Lisp,Dylan或Cecil等语言中使用),因为它只是一个方便的语法调用特别命名(但其他常规)方法:
len(s) == s.__len__()
Run Code Online (Sandbox Code Playgroud)
另请注意,这只是单一调度,即实际接收器(s在上面的代码中)确定调用的方法实现.甚至是一个假设
def call_special(receiver, *args, **keys):
return receiver.__call_special__(*args, **keys)
Run Code Online (Sandbox Code Playgroud)
仍然是单调度函数,因为在解析要调用的方法时仅使用接收器.其余的参数只是传递,但它们不会影响方法选择.
这与多分派不同,其中没有专用接收器,并且所有参数都用于查找要调用的实际方法实现.这就是实际上使整个事情变得有价值的东西.如果它只是一些奇怪的语法糖,没有人会打扰使用它,恕我直言.
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()
Run Code Online (Sandbox Code Playgroud)
在这个例子中,一个叫做的话
serialize_object(MyStuff(10, "hello world"), XMLStream())
Run Code Online (Sandbox Code Playgroud)
考虑两个参数以决定实际必须调用哪个方法.
对于Python中泛型函数的一个很好的使用场景,我建议阅读重构的代码,peak.security它为使用泛型函数(使用RuleDispatch)访问权限检查提供了一个非常优雅的解决方案.