Я бы порекомендовал библиотеку PEAK-Rules от P. Eby. Тем же автором (хотя и не рекомендуется) является пакет RuleDispatch (предшественник PEAK-Rules). Последний больше не поддерживается IIRC.
PEAK-Rules имеет много приятных особенностей, одна из которых заключается в том, что он (ну, не легко, но) расширяемый. Помимо «классической» отправки по типам «ony», в ней также предусмотрена отправка произвольных выражений в качестве «хранителей».
Функция len()
не является истинной обобщенной функцией (по крайней мере, в смысле упомянутых выше пакетов, а также в том смысле, что этот термин используется в таких языках, как Common Lisp , Dylan или Cecil ), поскольку это просто удобный синтаксис для вызова специально названного (но в остальном регулярного) метода:
len(s) == s.__len__()
Также обратите внимание, что это только одна отправка, то есть фактический получатель (s
в приведенном выше коде) определяет вызванную реализацию метода. И даже гипотетический
def call_special(receiver, *args, **keys):
return receiver.__call_special__(*args, **keys)
по-прежнему является функцией единой диспетчеризации, поскольку при разрешении вызываемого метода используется только получатель. Остальные аргументы просто передаются, но они не влияют на выбор метода.
Это отличается от множественной диспетчеризации, где нет выделенного получателя, и все аргументы используются для того, чтобы найти фактическую реализацию метода для вызова. Это то, что на самом деле делает все это стоящим. Если бы это был только какой-то странный синтаксический сахар, никто бы не стал его использовать, ИМХО.
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, я бы рекомендовал прочитать переработанный код peak.security
, который дает очень элегантное решение для проверки прав доступа с использованием универсальных функций (с использованием RuleDispatch
).