如何输入来自未声明基类的
@property
(使用 mixin 时经常发生)?
例如为了注释来自隐藏继承层次结构的“预期属性”,我使用:
class SomeMixin:
name: str
logger: Logger
def __init__(self):
super().__init__()
我们总是在继承层次结构中使用
SomeMixin
来证明self.name
和self.logger
类型的属性str
和Logger
。到目前为止,一切都很好。
如果要使用 mixin,其中
logger
由另一个类提供,实际上是一个属性,例如:
@property
def logger(self):
return self.__logger
如何在 mixin 中输入提示?我可以继续使用上面的现有属性类型提示,但随后在类型检查时收到“不兼容的覆盖”错误,因为
logger
实际上不是属性,例如:
class Base:
@property
def logger(self) -> Logger:
return Logger("foo")
class Derived(SomeMixin, Base):
pass
类型检查器会抱怨
Dervied
与 logger
的定义不兼容,例如,在 Pyright 中:
Base classes for class "Derived" define variable "logger" in incompatible wayPylancereportIncompatibleVariableOverride
foo.py(17, 9): Base class "Base" provides type "property", which is overridden
foo.py(9, 5): Base class "SomeMixin" overrides with type "Logger"
我可以使用类似的东西:
class SomeMixin:
name: str
logger: property
...但是
logger
具有类型 Any
并且我没有得到对其值进行类型检查的好处。
这是 python 的一个怪癖,
@property
和常规属性本质上被视为不同的类型。要解决您的问题,您需要在 SomeMixin
中指定 logger 是一个属性:
class Logger:
def __init__(self, s:str) -> None:
pass
class SomeMixin:
name: str
@property
def logger(self) -> Logger:
raise NotImplementedError
def __init__(self):
super().__init__()
class Base:
@property
def logger(self) -> Logger:
return Logger("foo")
class Derived(Base, SomeMixin):
pass
我还建议使用抽象基类来确保该属性被使用
SomeMixin
的类覆盖。这只是确保您无法在不将其与另一个类组合以覆盖该方法的情况下初始化 SomeMixin
:
from abc import ABC, abstractmethod
class Logger:
def __init__(self, s:str) -> None:
pass
class SomeMixin(ABC):
name: str
@property
@abstractmethod
def logger(self) -> Logger:
...
def __init__(self):
super().__init__()
class Base:
@property
def logger(self) -> Logger:
return Logger("foo")
class Derived(Base, SomeMixin):
pass
关于继承的旁注:请注意,我在
Base
中切换了 SomeMixin
和 Derived
- 这样 Base
就会覆盖 SomeMixin
,而不是相反。