我想专门为特定类键入提示参数,但排除任何子类。
class A:
pass
class B(A):
pass
def foo(obj: A):
pass
foo(B()) # I'd like the type checker to warn me here that it expects A, not B
这可能吗?如果是这样,怎么办?
(如果可以告诉我,我要怎么称呼,请加分。谷歌搜索没有帮助,但恐怕我使用了错误的术语来描述)
不,这是不可能的。
从根本上说,Python类型化生态系统假定您遵循Liskov substitution principle -假定在设计用于处理父级的位置替换子类始终是安全的。
它允许您在代码段中除了A实例之外还传递B实例,这只是这种原理在起作用的一个例子。
因此,如果您的子类B被设计为[[not来遵循Liskov替换原理,那么可能从一开始它就不是真正的A类,也不应该对其进行子类化。
您可以通过调整代码以使B正确遵循Liskov或通过使B停止对A的子类化,而改为使用组合而不是继承作为代码重用的机制来解决此问题。也就是说,使B保留A的实例作为字段并适当使用它。[如果遇到极少数情况,在不破坏Liskov的情况下合法地不可能继承A的情况,那么可以防止他人意外地继承它,您可以做的就是将A明确标记为final:
from typing import final
# If you want to support Python 3.7 or earlier, pip-install 'typing_extensions'
# and do 'from typing_extensions import final' instead
@final
class A: pass
class B(A): pass
这将使类型检查器报告有关B的定义的“ B无法子类A”错误。并且,如果通过更改/删除B
来修复该错误,则对foo(B())
的调用自然也应该无法键入-检查。