当我在以下代码上运行mypy时,我看到几个错误:
from typing import Callable, Type
def class_creator(outside_reference: Callable[[str], None]) -> Type[object]:
class SomeClass():
reference: Callable[[str], None]
def __init__(self) -> None:
self.reference = outside_reference
super().__init__()
def __str__(self):
self.reference("SomeClass instance")
return SomeClass
def callback(string: str) -> None:
print("Prepping: " + string)
instance = class_creator(callback)()
print(instance)
以下是错误:
test.py:9: error: Cannot assign to a method
test.py:9: error: Invalid self argument "SomeClass" to attribute function "reference" with type "Callable[[str], None]"
test.py:9: error: Incompatible types in assignment (expression has type "Callable[[str], None]", variable has type "Callable[[], None]")
第9行是self.reference = outside_reference
。
基本上,我只是误解了一些东西,但是我看不出我要去哪里。
这是最小的可复制参考。如果我将类型从Callable[[str], None]
更改为int
(并且实际上没有调用它),那么它运行得很好,并且没有显示任何错误。只有当我切换到Callable
时,它才会开始显示这些错误。
我的注释应该在这里什么?
答案 0 :(得分:2)
在https://github.com/python/mypy/issues/708中的问题得到解决之前,一种解决此问题的干净方法是使callable属性成为可选属性,并将其包装在带有assert的方法中:
from typing import Any, Callable, Optional
class SomeClass:
_reference: Optional[Callable[[], Any]]
def reference(self) -> Any:
assert self._reference is not None
return self._reference()
def __init__(self, reference):
self.reference = reference
c = SomeClass(lambda: 42)
print(c.reference())
$ mypy test.py
Success: no issues found in 1 source file
答案 1 :(得分:0)
暂时,MyPy不支持您这样做。在GitHub第708期中跟踪了对这种模式的支持:https://github.com/python/mypy/issues/708
在大多数情况下,最接近的模式是使用诸如execute
之类的方法定义一个抽象类,然后让调用者将其实现与该类进行实例化,实例化此实例,并将实例作为参数而不是回调。您可以在较旧的Java代码库(Java 8之前)中看到这种方法,这是匿名内部类的常见用例。当然,这很乏味。
或者,您可以简单地要求mypy忽略违规行为。
答案 2 :(得分:0)
一种类似但更短的解决方法是使用Union
类型注释成员,复制Callable
类型:
from typing import Callable, Union
class SomeClass:
reference: Union[Callable[[], int], Callable[[], int]]
def __init__(self, reference: Callable[[], int]):
self.reference = reference
c = SomeClass(lambda: 42)
print(c.reference())