[英]Python Typing for a Callable Class
I have something like我有类似的东西
class Class1(Class2):
def __init__(
self,
use_class = Class3
...
):
do something
So Class1
inherits from Class2
and needs a parameter use_class
which is set to Class3
by default.所以Class1
继承自Class2
并且需要一个默认设置为Class3
的参数use_class
。 Class3
accepts floats
and/or strings
as input. Class3
接受floats
和/或strings
作为输入。 But there can be other classes set to use instead of Class3
.但是可以使用其他类来代替Class3
。 They also accept floats
and/or strings
as input.它们还接受floats
和/或strings
作为输入。 However, they all have to inherit from the same Class4
.但是,它们都必须从同一个Class4
继承。 Furthermore, each of those classes that are valid inputs for use_class
doesn't return anything.此外,作为use_class
有效输入的每个类都不会返回任何内容。 So my guess for typing would be所以我对打字的猜测是
class Class1(Class2):
def __init__(
self,
use_class: Callable[[Union[float, str]], None] = Class3
...
):
do something
But this doesn't incorporate the fact that the class given as use_class
has to inherit from Class4
in order for the code to run.但这并没有包含这样一个事实,即作为use_class
给出的类必须从Class4
继承才能运行代码。 Am I missing something here?我在这里错过了什么吗? I hope this question makes sense, any help or pointers are greatly appreciated.我希望这个问题有意义,非常感谢任何帮助或指示。
We can do either of these, but not both.我们可以做其中任何一个,但不能同时做。
To require that it be a subclass of Class4, we'd use Type
for the standard nominal typing:为了要求它是 Class4 的子类,我们将Type
用于标准的名义类型:
IsClass4 = Type[Class4]
And requiring that the value itself is a callable accepting certain inputs can be handled by structural typing via the Callable
you suggested, or simply Protocol
:并且要求值本身是一个可调用的接受某些输入,可以通过您建议的Callable
或简单的Protocol
结构类型来处理:
class MostlyWorks(Protocol):
def __call__(self, value: float | str) -> Class4:
...
Ideally, we'd like to do both via an intersection type :理想情况下,我们希望通过交集类型来实现这两者:
WhatWeWant = IsClass4 & AcceptsFloatsStrings
They're working on a PEP, but it's going to be some time.他们正在研究 PEP,但这需要一些时间。
Two thoughts on this: Python type checkers are often quite loose or even buggy, and there's not an absolutely canonical meaning for annotations.对此有两个想法:Python 类型检查器通常非常松散甚至有问题,并且注释没有绝对规范的含义。 They were designed to catch dumb mistakes in existing codebases, and to make code a bit more self-documenting.它们旨在捕捉现有代码库中的愚蠢错误,并使代码更具自我记录性。
This is why I'd advise against going too deep down the annotations rabbit hole.这就是为什么我建议不要在注释兔子洞中走得太深。
Second thought: imagine the type checker is a rather dim colleague such that if you can explain it to the type checker without using advanced techniques, your code will be clear and readable.第二个想法:想象类型检查器是一个相当昏暗的同事,如果你可以在不使用高级技术的情况下向类型检查器解释它,你的代码将是清晰易读的。
Here you're mixing nominal typing, structural typing, and you're requiring a Type[...]
instance.在这里,您混合了名义类型、结构类型,并且您需要一个Type[...]
实例。 That's tricky stuff.这是棘手的事情。
For instance, suppose you want use_class
to be a subclass of Class4
so you can call a class method on it.例如,假设您希望use_class
是Class4
的子类,因此您可以在其上调用类方法。
What if we don't need this to be a class
?如果我们不需要这是一个class
怎么办? What if it's just a Plain Old Python Object that just looks like one:如果它只是一个看起来像一个普通的旧 Python 对象怎么办:
class FakeClass(Protocol):
def __call__(self, value: float | str) -> Class4:
...
def works_like_classmethod(self, woah: Class77) -> str:
...
This gets us back to a fairly standard pattern, and one that explicitly lays out what your code will do with this thing.这让我们回到了一个相当标准的模式,并且明确地列出了你的代码将如何处理这件事。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.