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
一类.换句话说,whenC
是类的名称,使用C
注释参数声明参数是C
(或子类的C
)的实例,但是使用Type[C]
参数注释声明参数是派生自的类对象C
(或者C
自己).
小智 36
如果我们查看模块Type
的描述typing
,那么我们会看到以下文档:
可用于注释类对象的特殊构造。
例如,假设我们有以下类:
Run Code Online (Sandbox Code Playgroud)class User: ... # Abstract base for User classes class BasicUser(User): ... class ProUser(User): ... class TeamUser(User): ...
还有一个函数,它接受一个 User 子类的类参数并返回相应类的实例:
Run Code Online (Sandbox Code Playgroud)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)
此时,类型检查器知道 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
来纠正这种情况。然后在声明为类型的地方使用它。TypeVar
bound
BaseClass
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)
希望这会有所帮助。
我找到了解决方案。使用:
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)