继承类型和成员重载的Python类型注释问题

继承类型和成员重载的Python类型注释问题,python,python-3.x,mypy,type-annotation,Python,Python 3.x,Mypy,Type Annotation,请参阅下面的例子,使用Python3.7,我无法找到正确注释的方法。注释错误显示在注释中,由mypy给出 我有一个实现“泛型成员”的“泛型类”。以及继承该结构的具体类和成员 具体成员可以有其他方法,并为构造函数使用不同的参数 怎样才能正确地诠释这一点 非常感谢 import abc import typing class ParentProvider(metaclass=abc.ABCMeta): def __init__(self) -> None: pa

请参阅下面的例子,使用Python3.7,我无法找到正确注释的方法。注释错误显示在注释中,由mypy给出

  • 我有一个实现“泛型成员”的“泛型类”。以及继承该结构的具体类和成员
  • 具体成员可以有其他方法,并为构造函数使用不同的参数
怎样才能正确地诠释这一点

非常感谢

import abc
import typing


class ParentProvider(metaclass=abc.ABCMeta):
    def __init__(self) -> None:
        pass


class ChildProvider(ParentProvider):
    def __init__(self, who: str) -> None:
        ParentProvider.__init__(self)
        self._who: str = who

    @property
    def p(self) -> str:
        return "Hello %s" % self._who


class Parent(metaclass=abc.ABCMeta):
    @property
    @abc.abstractmethod
    def providerType(self) -> typing.Type[ParentProvider]:
        pass

    @property
    @abc.abstractmethod
    def providerKwargs(self) -> typing.Dict[str, typing.Any]:
        pass

    @property
    def provider(self) -> ParentProvider:
        # How to avoid the following error?
        # error: Too many arguments for "ParentProvider"  [call-arg]
        return self.providerType(**self.providerKwargs)

    @abc.abstractmethod
    def useIt(self) -> None:
        pass


class Child(Parent):
    @property
    def providerType(self) -> typing.Type[ParentProvider]:
        # Using Type[ChildProvider] instead Type[ParentProvider]
        # doesn't helps
        return ChildProvider

    @property
    def providerKwargs(self) -> typing.Dict[str, typing.Any]:
        return dict(who='world')

    def useIt(self) -> None:
        # How to avoid the following error?
        # error: "ParentProvider" has no attribute "p"  [attr-defined]
        print(self.provider.p)


if __name__ == "__main__":
    Child().useIt()
我有一个实现“泛型成员”的“泛型类”

然后将其标记为:

from typing import Generic, TypeVar


_T = TypeVar('_T', bound='ParentProvider')


class Parent(Generic[_T], metaclass=abc.ABCMeta):
    @property
    @abc.abstractmethod
    def providerType(self) -> typing.Type[_T]:
        pass

    @property
    @abc.abstractmethod
    def providerKwargs(self) -> typing.Dict[str, typing.Any]:
        pass

    @property
    def provider(self) -> _T:
        return self.providerType(**self.providerKwargs)

    @abc.abstractmethod
    def useIt(self) -> None:
        pass
现在,特定的
impl变为:

class Child(Parent[ChildProvider]):
    @property
    def providerType(self) -> typing.Type[ChildProvider]:
        return ChildProvider

    @property
    def providerKwargs(self) -> typing.Dict[str, typing.Any]:
        return dict(who='world')

    def useIt(self) -> None:
        print(self.provider.p)
如何避免以下错误

error: Too many arguments for "ParentProvider"  [call-arg]
Parent.\uuuu init\uuuu
签名不允许传递任何参数-您可以使用

class ParentProvider(metaclass=abc.ABCMeta):
    def __init__(self, *args, **kwargs) -> None:
        pass
(或只是

如果不希望允许在提供程序(构造函数)中传递位置参数

我有一个实现“泛型成员”的“泛型类”

然后将其标记为:

from typing import Generic, TypeVar


_T = TypeVar('_T', bound='ParentProvider')


class Parent(Generic[_T], metaclass=abc.ABCMeta):
    @property
    @abc.abstractmethod
    def providerType(self) -> typing.Type[_T]:
        pass

    @property
    @abc.abstractmethod
    def providerKwargs(self) -> typing.Dict[str, typing.Any]:
        pass

    @property
    def provider(self) -> _T:
        return self.providerType(**self.providerKwargs)

    @abc.abstractmethod
    def useIt(self) -> None:
        pass
现在,特定的
impl变为:

class Child(Parent[ChildProvider]):
    @property
    def providerType(self) -> typing.Type[ChildProvider]:
        return ChildProvider

    @property
    def providerKwargs(self) -> typing.Dict[str, typing.Any]:
        return dict(who='world')

    def useIt(self) -> None:
        print(self.provider.p)
如何避免以下错误

error: Too many arguments for "ParentProvider"  [call-arg]
Parent.\uuuu init\uuuu
签名不允许传递任何参数-您可以使用

class ParentProvider(metaclass=abc.ABCMeta):
    def __init__(self, *args, **kwargs) -> None:
        pass
(或只是


如果不想允许在提供程序构造函数中传递位置参数)。

对于“Child.useIt”方法,在使用self.provider.p之前,解决方法是“assert-isinstance(self.provider,self.providerType)”。但这在Parent.provider中不起作用,因为它还不知道最终的providerType类型。您将关键字参数传递给
providerType
,但未将其定义为接受任何参数
providerKwargs
是一种方法,但您并没有调用它(您将其视为
dict
本身)。谢谢@chepner。父级在Parent.provider属性中安装提供程序时会使用providerKwargs。谁使用它并不重要,因为您使用不正确。如果它是一个方法,则必须调用它:
返回self.providerType(**self.providerKwargs())
。您仍然需要更改
providerType
的签名以接受关键字参数。@chepner providerKwargs是一个属性…对于“Child.useIt”方法,在使用self.provider.p之前,解决方法是“assert-isinstance(self.provider,self.providerType)”。但这在Parent.provider中不起作用,因为它还不知道最终的providerType类型。您将关键字参数传递给
providerType
,但未将其定义为接受任何参数
providerKwargs
是一种方法,但您并没有调用它(您将其视为
dict
本身)。谢谢@chepner。父级在Parent.provider属性中安装提供程序时会使用providerKwargs。谁使用它并不重要,因为您使用不正确。如果它是一个方法,则必须调用它:
返回self.providerType(**self.providerKwargs())
。您仍然需要更改
providerType
的签名以接受关键字参数。@chepner providerKwargs是一个属性…很乐意帮助!:-)很乐意帮忙!:-)