Pycharm 类型提示警告 类 而不是实例
Pycharm type hints warning for classes instead of instances
我试图理解为什么 pycharm 在使用以静态方法作为参数的抽象 class 实现时警告我类型错误。
为了演示我会做一个简单的例子。假设我有一个带有一个方法的抽象 class,一个实现(继承)这个类似接口的抽象 class 的 class,以及一个获取应该用作参数的实现的方法。
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 没有抱怨它。
问题是我有很多 class 的实现,不想为每个实现创建一个实例,所以我将这个 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")
这仍然以相同的方式工作,但显然因为函数调用中的参数现在是 class 名称而不是它的实例,Pycharm 抱怨说:
Expected type 'GreetingMakerBase', got 'Type[HelloGreetingMaker]' instead.
有没有一种方法可以解决此警告而无需实例化 HelloGreetingMaker
class?
您没有创建实例,并且您的类型提示暗示该函数只接受实例(某种类型 GreetingMakerBase
,而不是 GreetingMakerBase
本身或子 class的)。
如果你想指定只有 GreetingMakerBase
本身是一个可接受的论点,为什么要把它作为一个论点呢?只需在内部调用 class 的函数即可。
无论如何,python 3.8 有一些新的打字改进可以帮助您。您可以指定 literal type hint:
from typing import Literal
def print_greeting(maker: Literal[GreetingMakerBase], name):
print(maker.make_greeting(name))
如果您需要在其他(早于 3.8)python 版本中支持此类型提示,则必须安装 typing extensions:
pip install typing-extensions
当您执行 print_greeting(HelloGreetingMaker, "John")
时,您不会尝试传入 HelloGreetingMaker 的 实例 。相反,您传递的是 class 本身。
我们输入的方式是使用 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 docs on the typing module and the mypy docs 有更多详细信息和示例。
我试图理解为什么 pycharm 在使用以静态方法作为参数的抽象 class 实现时警告我类型错误。
为了演示我会做一个简单的例子。假设我有一个带有一个方法的抽象 class,一个实现(继承)这个类似接口的抽象 class 的 class,以及一个获取应该用作参数的实现的方法。
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 没有抱怨它。
问题是我有很多 class 的实现,不想为每个实现创建一个实例,所以我将这个 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")
这仍然以相同的方式工作,但显然因为函数调用中的参数现在是 class 名称而不是它的实例,Pycharm 抱怨说:
Expected type 'GreetingMakerBase', got 'Type[HelloGreetingMaker]' instead.
有没有一种方法可以解决此警告而无需实例化 HelloGreetingMaker
class?
您没有创建实例,并且您的类型提示暗示该函数只接受实例(某种类型 GreetingMakerBase
,而不是 GreetingMakerBase
本身或子 class的)。
如果你想指定只有 GreetingMakerBase
本身是一个可接受的论点,为什么要把它作为一个论点呢?只需在内部调用 class 的函数即可。
无论如何,python 3.8 有一些新的打字改进可以帮助您。您可以指定 literal type hint:
from typing import Literal
def print_greeting(maker: Literal[GreetingMakerBase], name):
print(maker.make_greeting(name))
如果您需要在其他(早于 3.8)python 版本中支持此类型提示,则必须安装 typing extensions:
pip install typing-extensions
当您执行 print_greeting(HelloGreetingMaker, "John")
时,您不会尝试传入 HelloGreetingMaker 的 实例 。相反,您传递的是 class 本身。
我们输入的方式是使用 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 docs on the typing module and the mypy docs 有更多详细信息和示例。