类型提示中的子类

use*_*030 20 python subclass type-hinting

我想允许使用Python 3的类型提示来接受某个类的子类.例如:

class A:
    pass

class B(A):
    pass

class C(A):
    pass

def process_any_subclass_type_of_A(cls: A):
    if cls == B:
        # do something
    elif cls == C:
        # do something else
Run Code Online (Sandbox Code Playgroud)

现在输入以下代码时:

process_any_subclass_type_of_A(B)
Run Code Online (Sandbox Code Playgroud)

我得到一个PyCharm IDE提示'预期类型A,而不是类型[B].

如何在此处更改类型提示以接受A的任何子类型?

根据这个(https://www.python.org/dev/peps/pep-0484/#type-definition-syntax,"该参数也接受其类型是特定参数类型的子类型的表达式.") ,我明白我的解决方案(cls: A)应该有效吗?

Ash*_*ary 36

当你这样做时cls: A,你会说这cls是一个类型的实例A.使其适用于类型或其子类型使用typing.Type.

from typing import Type
def process_any_subclass_type_of_A(cls: Type[A]):
    pass
Run Code Online (Sandbox Code Playgroud)

类对象的类型 :

有时您想谈论从给定类继承的类对象.这可以被拼写为Type[C]其中C一类.换句话说,when C是类的名称,使用C注释参数声明参数是C(或子类的C)的实例,但是使用Type[C]参数注释声明参数是派生自的类对象C(或者C自己).

  • 如果需要 A 的任何子类的实例,那会是什么样子? (17认同)

小智 36

如果我们查看模块Type的描述typing,那么我们会看到以下文档:

可用于注释类对象的特殊构造。

例如,假设我们有以下类:

 class User: ...  # Abstract base for User classes
 class BasicUser(User): ...
 class ProUser(User): ...
 class TeamUser(User): ...
Run Code Online (Sandbox Code Playgroud)

还有一个函数,它接受一个 User 子类的类参数并返回相应类的实例:

 U = TypeVar('U', bound=User)
 def new_user(user_class: Type[U]) -> U:
     user = user_class()
     # (Here we could write the user object to a database)
     return user

 joe = new_user(BasicUser)
Run Code Online (Sandbox Code Playgroud)

此时,类型检查器知道 joe 的类型为 BasicUser。

基于此,我可以想象一个综合示例,可以重现 PyCharm 中类型提示错误的问题。

 class User: ...  # Abstract base for User classes
 class BasicUser(User): ...
 class ProUser(User): ...
 class TeamUser(User): ...
Run Code Online (Sandbox Code Playgroud)

但我们在文档中看到,可以通过使用with参数Type来纠正这种情况。然后在声明为类型的地方使用它。TypeVarboundBaseClass

 U = TypeVar('U', bound=User)
 def new_user(user_class: Type[U]) -> U:
     user = user_class()
     # (Here we could write the user object to a database)
     return user

 joe = new_user(BasicUser)
Run Code Online (Sandbox Code Playgroud)

希望这会有所帮助。

  • @rjurney 当您需要指示类型是 Foo 类本身(而不是 Foo 类的实例)时,您可以使用 Type[Foo] 。当您需要指示一个位置的类型必须与另一位置的类型相同(即返回类型必须遵循参数类型,或者一个参数必须是另一个参数的类的实例)时,可以使用 TypeVar (3认同)

use*_*030 7

我找到了解决方案。使用:

from typing import Type
def process_any_subclass_type_of_A(cls: Type[A]):
    pass
Run Code Online (Sandbox Code Playgroud)

如上面的PEP中所述,期望的行为将在那里。


小智 7

Type[A] 还接受类本身,但这并不总是需要的。

如果你希望你的函数只接受子类,你应该使用NewType,比如

class A:
    pass

B = NewType('B', A)

def foo(cls: Type[B]):
   ...
Run Code Online (Sandbox Code Playgroud)