我有以下代码:
from typing import Callable
MyCallable = Callable[[object], int]
MyCallableSubclass = Callable[['MyObject'], int]
def get_id(obj: object) -> int:
return id(obj)
def get_id_subclass(obj: 'MyObject') -> int:
return id(obj)
def run_mycallable_function_on_object(obj: object, func: MyCallable) -> int:
return func(obj)
class MyObject(object):
'''Object that is a direct subclass of `object`'''
pass
my_object = MyObject()
# works just fine
run_mycallable_function_on_object(my_object, get_id)
# Does not work (it runs, but Mypy raises the following error:)
# Argument 2 to "run_mycallable_function_on_object" has incompatible type "Callable[[MyObject], int]"; expected "Callable[[object], int]"
run_mycallable_function_on_object(my_object, get_id_subclass)
既然MyObject
从object
继承,为什么MyCallableSubclass
不能在MyCallable
的每个地方工作?你知道吗
我读了一些关于Liskov substitution principle的书,也参考了Mypy docs关于协方差和逆方差的书。然而,即使在文档中,他们也给出了一个非常相似的例子
Callable
is an example of type that behaves contravariant in types of arguments, namelyCallable[[Employee], int]
is a subtype ofCallable[[Manager], int]
.
那么为什么用Callable[[MyObject], int]
而不是Callable[[object], int]
在Mypy中抛出错误呢?你知道吗
总的来说,我有两个问题:
当我写这个问题的时候,我意识到了问题的答案,所以我想我还是会问这个问题,然后再回答,这样可以节省人们以后问类似问题的时间。你知道吗
发生什么事了?
请注意Mypy文档的最后一个示例:
这里,
Manager
子类来自Employee
。也就是说,如果某个东西期望某个功能可以接纳管理者,那么它得到的功能如果过度概括,可以接纳任何员工,就没关系了,因为它肯定会接纳管理者。你知道吗然而,在我们的例子中,
MyObject
子类来自object
。因此,如果某个东西期望一个函数可以接受对象,那么如果它得到的函数超过了并且只能接受MyObject
,那就不好了为什么?设想一个名为
NotMyObject
的类继承自object
,但不继承自MyObject
。如果一个函数应该能够接受任何对象,那么它应该能够同时接受NotMyObject
和MyObject
两个对象。但是,特定于的函数只能接受MyObject
对象,因此在这种情况下不起作用。你知道吗我该怎么修?
Mypy是正确的。您需要使用更具体的函数(
MyCallableSubclass
)作为类型,否则您的代码可能会有bug,或者您的键入不正确。你知道吗相关问题 更多 >
编程相关推荐