抽象
此 PEP 建议使函数对象可下标以用于键入目的。这样做 使开发人员能够显式控制类型检查器生成的类型,其中 双向推理(允许匿名的参数类型 功能有待推断)和专业化以外的其他方法是不够的。它 还使函数在能力上与常规类保持一致 可下标。
赋予动机
未知类型
目前,无法将类型参数推断为泛型函数 某些情况:
def make_list[T](*args: T) -> list[T]: ...reveal_type(make_list()) # type checker cannot infer a meaningful type for T
使 subscriptable 的实例允许此构造函数 键入:FunctionType
reveal_type(make_list[int]()) # type is list[int]
目前,您必须使用赋值来提供精确类型:
x: list[int] = make_list()reveal_type(x) # type is list[int]
但是这段代码不必要地冗长,占用了多个行的简单函数 叫。
同样,在这个例子中,目前无法有意义地推断,所以 无额外分配的非类型化:Tx
def factory[T](func: Callable[[T], Any]) -> Foo[T]: ...reveal_type(factory(lambda x: "Hello World" * x))
但是,如果函数对象是可下标的,则可以给出更具体的类型:
reveal_type(factory[int](lambda x: "Hello World" * x)) # type is Foo[int]
无法判定的推理
甚至在有些情况下,子类关系使类型推断变得不可能。然而 如果可以对函数进行专业化,则类型检查器可以推断出有意义的类型。
def foo[T](x: Sequence[T] | T) -> list[T]: ...reveal_type(foo[bytes](b"hello"))
目前,类型检查器不会始终如一地在此处合成类型。
不可解析类型参数
目前,对于非专用文字,无法确定 类似情况:
def foo[T](x: list[T]) -> T: ...reveal_type(foo([])) # type checker cannot infer T (yet again)
reveal_type(foo[int]([])) # type is int
在必须传递特定类型的情况下进行指定也很有用 事先到函数:
words = ["hello", "world"]foo[int](words) # Invalid: list[str] is incompatible with list[int]
允许订阅使函数和方法与泛型类一致,其中 他们还没有。虽然所有提议的更改都可以使用 可调用的泛型类,语法糖将非常受欢迎。
因此,将功能专业化并将其用作新工厂是可以的
make_int_list = make_list[int]reveal_type(make_int_list()) # type is list[int]
单态化和再化
这个提议也为单态化和具体化类型打开了大门。
这将允许一个轶事已经多次请求的功能。
请注意,此功能不是由 PEP 提出的,但可能会在 未来。
此类功能的语法可能如下所示:
def foo[T](): return T.__value__assert foo[int]() is int
理由
此 PEP 中的函数对象用于引用 、 、 和 。FunctionTypeMethodTypeBuiltinFunctionTypeBuiltinMethodTypeMethodWrapperType
因为你应该能够写:MethodType
class Foo: def make_list[T](self, *args: T) -> list[T]: ...Foo().make_list[int]()
并让它的工作方式类似于 .FunctionType
对于 ,所以内置泛型函数(例如 和 ) 像 Python 中定义的一样工作。内置函数的行为应与 尽可能用 Python 实现的函数。BuiltinFunctionTypemaxmin
BuiltinMethodType与 是相同的类型。BuiltinFunctionType
MethodWrapperType(例如,类型 ) 可用于 通用的魔术方法。object().__str__
规范
函数对象应实现以允许在运行时进行订阅 并返回一个实例 with set 作为 可调用,并作为类型传递。__getitem__types.GenericAlias__origin____args__
类型检查器应支持下标函数,并了解参数 传递给函数订阅应遵循与泛型可调用对象相同的规则 类。
设置
目前,是设置在 创建被调用类的实例,例如__orig_class__GenericAlias.__call__GenericAlias
class Foo[T]: ...assert Foo[int]().__orig_class__ == Foo[int]
目前,是无条件设置的;但是,为了避免潜在的 擦除任何创建的实例,如果 任何函数对象的实例。__orig_class____origin__
如果没有此更改,以下代码片段将在运行时失败,就像 NOT 一样。__orig_class__bar[str]Foo[int]
def bar[U](): return Foo[int]()assert bar[str]().__orig_class__ == Foo[int]
与的互动
重载函数的工作方式应该与现有函数大致相同,因为它们对 运行时类型。唯一的变化是可以决定更多情况,并且 行为/重载可以由开发人员指定,而不是留给排序 的过载/联合。
向后兼容性
目前,这些类不可子类化,因此没有向后类 关于已经实现的类的兼容性问题。__getitem__
确认
感谢 Alex Waygood 和 Jelle Zijlstra 对此 PEP 和 Guido 的反馈 举一些激励人心的例子。
版权
本文档置于公有领域或采用 CC0-1.0-Universal 许可协议, 以更宽松的方式为准。
文章声明:以上内容(如有图片或视频在内)除非注明,否则均为腾龙猫勺儿原创文章,转载或复制请以超链接形式并注明出处。
本文作者:猫勺本文链接:https://www.jo6.cn/post/69.html
还没有评论,来说两句吧...