我试图理解为什么 pycharm 在使用以静态方法作为参数的抽象类的实现时警告我类型错误。
为了演示,我将举一个简单的例子。假设我有一个带有一个方法的抽象类,一个实现(继承)这个类似接口的抽象类的类,以及一个获取它应该用作参数的实现的方法。
import abc
class GreetingMakerBase(abc.ABC):
@abc.abstractmethod
def make_greeting(self, name: str) -> str:
""" Makes greeting string with name of person """
class HelloGreetingMaker(GreetingMakerBase):
def make_greeting(self, name: str) -> str:
return "Hello {}!".format(name)
def print_greeting(maker: GreetingMakerBase, name):
print(maker.make_greeting(name))
hello_maker = HelloGreetingMaker()
print_greeting(hello_maker, "John")
请注意,在
print_greeting
的类型提示中,我使用了 GreetingMakerBase
,因为 isinstance(hello_maker, GreetingMakerBase) is True
Pycharm 没有抱怨它。
问题是我的类有很多实现,并且不想为每个实现创建实例,所以我会将这个
make_greeting
方法设为静态,如下所示:
class GreetingMakerBase(abc.ABC):
@staticmethod
@abc.abstractmethod
def make_greeting(name: str) -> str:
""" Makes greeting string with name of person """
class HelloGreetingMaker(GreetingMakerBase):
@staticmethod
def make_greeting(name: str) -> str:
return "Hello {}!".format(name)
def print_greeting(maker: GreetingMakerBase, name):
print(maker.make_greeting(name))
print_greeting(HelloGreetingMaker, "John")
这仍然以相同的方式工作,但显然因为函数调用中的参数现在是类名而不是它的实例,Pycharm 抱怨:
Expected type 'GreetingMakerBase', got 'Type[HelloGreetingMaker]' instead.
有没有办法可以解决此警告,而无需实例化
HelloGreetingMaker
类?
当您执行
print_greeting(HelloGreetingMaker, "John")
时,您并不是试图传入 HelloGreetingMaker 的 实例。相反,您正在传递课程本身。
我们输入的方式是使用
Type[T]
,它指定您想要 T 的类型,而不是 T 的实例。例如:
from typing import Type
import abc
class GreetingMakerBase(abc.ABC):
@staticmethod
@abc.abstractmethod
def make_greeting(name: str) -> str:
""" Makes greeting string with name of person """
class HelloGreetingMaker(GreetingMakerBase):
@staticmethod
def make_greeting(name: str) -> str:
return "Hello {}!".format(name)
def print_greeting(maker: Type[GreetingMakerBase], name):
print(maker.make_greeting(name))
# Type checks!
print_greeting(HelloGreetingMaker, "John")
请注意,
Type[HelloGreetingMaker]
被认为与 Type[GreetingMakerBase]
兼容——Type[T]
相对于 T 是协变的。
如果您想了解更多信息,有关打字模块的 Python 文档 和 mypy 文档 有更多详细信息和示例。
您没有创建实例,并且您的类型提示意味着该函数仅接受实例(
GreetingMakerBase
类型的东西,而不是GreetingMakerBase
本身或其子类)。
如果您想指定只有
GreetingMakerBase
本身是可接受的参数,为什么还要将其作为参数呢?只需让函数在内部调用该类即可。
无论如何,Python 3.8 有一些新的打字改进可以帮助你。您可以指定文字类型提示:
from typing import Literal
def print_greeting(maker: Literal[GreetingMakerBase], name):
print(maker.make_greeting(name))
如果您需要在其他(3.8 之前)Python 版本中支持此类型提示,则必须安装 打字扩展:
pip install typing-extensions