未提供项目描述
项目描述
Dyndis
关于
Dyndis是一个库,可以轻松地流畅地创建多分派函数和方法。它最初是为非严格分层系统中的运算符而制作的,但也可以用于任何其他多分派目的。
简单示例
from typing import Union
from dyndis import MultiDispatch
@MultiDispatch
def foo(a, b):
# default implementation in case no candidates match
raise TypeError
@foo.register()
def _(a: int, b: Union[int, str]):
return "overload 1 <int, (int|str)>"
@foo.register()
def _(a: object, b: float):
return "overload 2 <any, float>"
foo(1, "hello") # overload 1
foo(("any", "object", "here"), 2.5) # overload 2
foo(2, 3) # overload 1
foo(2, 3.0) # overload 2
功能
- 动态升级。
- 无缝使用类型提示和类型变量。
- 高级数据结构以最小化候选查找时间。
- 实现者接口使其易于创建类似于方法的重载
它是如何工作的?
中心类(用户只需导入一个)是MultiDispatch
。 MultiDispatch
包含按优先级和它们接受的参数类型排序的候选实现。当调用MultiDispatch
时,它调用其相关候选者(按优先级、继承和兼容性排序,下面将详细说明),直到其中一个返回非NotImplemented
的返回值。
查找顺序
所有类型参数的候选者(<T0, T1, T2..., TN>)按以下顺序排序
- 任何与键中任何类型不兼容的候选者都被排除。也就是说,对于任何0 <=
i
<= N,如果候选者的参数i
的类型约束不是Ti的超类,则该候选者被排除。 - 候选者按继承排序。如果一个候选者的所有参数类型都是另一个的相应参数类型的子类(或同样受其覆盖),则认为该候选者继承自另一个候选者。一个候选者将在它继承的任何其他候选者之前被考虑。例如,<int,object>将先于<Number, object>被考虑。
如果有两个候选者不相互继承,则会抛出一个异常(类型为 dyndis.AmbiguityError
),除非首先成功执行优先级更高的候选者。
如果候选者返回 NotImplemented
,则尝试下一个候选者。如果没有候选者被接受或所有候选者都返回了 NotImplemented
,则调用默认实现。
拓扑和缓存
dyndis
使用拓扑集对所有候选者按参数类型进行排序,这样就可以在不产生任何开销的情况下忽略大多数候选者。
对于每次查找都考虑所有这些候选者会非常慢,并且很快就会变得笨重。因此,每个 MultiDispatch
都会自动缓存这些计算,包括排序和处理候选者。
默认参数、可变参数和关键字参数
- 如果候选者具有具有默认值和类型注解的位置参数,则默认值将被忽略以用于候选者解析。
- 如果候选者具有可变位置参数,则会被忽略。当从
MultiDispatch
调用时,其值始终为()
。 - 如果候选者具有仅关键字参数,则该参数不会用于候选者类型,它必须在调用
MultiDispatch
时具有默认值或设置。 - 如果候选者具有可变关键字参数,则会被忽略。当从
MultiDispatch
调用时,其值将根据(类型忽略的)关键字参数来确定。
通常,当使用关键字参数调用 MultiDispatch
时,这些参数不会用于候选者解析,并且会原样发送给每个尝试的候选者。
实现者
Implementor
是一个描述符,它使得在类内部创建方法样式的候选者变得容易。
from dyndis import MultiDispatch
@MultiDispatch
def add(self, other):
return NotImplemented
class Base:
__add__ = add
class A(Base):
@add.implement(__qualname__)
def add(self, other: 'A'):
# in implementor methods, `self` is assumed to be of the owner class
return "A+A"
@add.implement(__qualname__)
def add(self, other: Base):
return "A+Base"
class B(Base):
@add.implement(__qualname__)
def add(self, other: A):
return 'B+A'
a = A()
b = B()
base = Base()
a + b # A+B
a + base # A+Base
a + a # A+A
特殊类型注解
类型注解可以是任何类型,或者以下特殊值之一
typing.Union
:接受包含类型中的任何类型的参数typing.Optional
:接受包含类型或None
typing.Any
:被认为是任何类型的超类型,包括object
- typing 的任何别名和抽象类,如
typing.List
或typing.Sized
:等同于其原始类型(注意,专门化的别名如typing.List[str]
是无效的) typing.TypeVar
:见下文None
,...
,NotImplemented
:等同于其类型
TypeVar
注解
参数还可以用 typing.TypeVar
注解。这些变量在遇到时会贪婪地绑定,并且在第一次绑定时就被视为匹配。第一次绑定后,它们被视为所有方面的绑定类型(或 TypeVar
的最低约束)。
from typing import TypeVar, Any
from dyndis import MultiDispatch
T = TypeVar('T')
@MultiDispatch
def foo(*args):
raise TypeError
@foo.register()
def _(a: T, b: T):
return "type(b) <= type(a)"
@foo.register()
def _(a: Any, b: Any):
return "type(b) </= type(a"
foo(1, 1) # <=
foo(1, True) # <=
foo(2, 'a') # </=
foo(object(), object()) # <=
# type variables bind greedily, meaning their exact value will be equal to the first type they encounter
foo(False, 2) # </=
项目详情
下载文件
下载适合您平台的自定义文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。
源码分发
构建分发
dyndis-0.2.0.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 703d6efd4768e992689f119143fdf109cd0f1bee8fd58292f49d1abdeb2626dd |
|
MD5 | a537f4000901ed3a34ca10d9669e2c2a |
|
BLAKE2b-256 | 19aa5c05f4c1236448975b687064ad2782f0a56ed3ee8cf9406cd87e8f9e7881 |
dyndis-0.2.0-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | f675698fc75f8b9ecce4113b99df24ede10fda581c67adc1c35727832e361889 |
|
MD5 | 38d0b866147d3170b593e3c85e8d7ad2 |
|
BLAKE2b-256 | 27a8a65d7c275d1dbc24404e798d77ab6cf24370087d8520a6b73e4b2e8153b8 |