简体   繁体   English

子类覆盖具有父属性子类型的属性

[英]Subclass overriding attribute with subtype of parent's attribute

class B:
    pass


class InheritsB1(B):
    pass


class InheritsB2(B):
    pass


class A:
    prop: list[B]


class InheritsA1(A):
    prop: list[InheritsB1]


class InheritsA2(A):
    prop: list[InheritsB2]

With this code mypy raises Incompatible types in assignment (expression has type "List[InheritsB2]", base class "A" defined the type as "List[B]") .使用此代码,mypy 引发Incompatible types in assignment (expression has type "List[InheritsB2]", base class "A" defined the type as "List[B]")

How can I make this work?我怎样才能使这项工作?

InheritsB1 is a subclass of B , so list[InheritsB1] is always a list of B . InheritsB1B的子类,因此list[InheritsB1]始终是B的列表。 How can I tell mypy that it's not incompatible?我如何告诉 mypy 它不是不兼容的? Or, how can I tell mypy that the prop in A is "list of B or any specific subclass of B "?或者,我如何告诉 mypy A中的prop是“ B的列表或B的任何特定子类”?

I understand the issue here: mypy trouble with inheritance of objects in lists .我了解这里的问题: mypy trouble with inheritance of objects in lists But in this case I want the prop object to be a list of a specific instances ( B or any subclass of B ).但在这种情况下,我希望prop object 成为特定实例( BB的任何子类)的列表。 I know it will never be mixed, as in it will always be list[B] or list[SubclassOfB1] or list[SubclassOfB2] , never list[SubclassOfB1 | SubclassOfB2]我知道它永远不会混合,因为它永远是list[B]list[SubclassOfB1]list[SubclassOfB2] ,永远不会list[SubclassOfB1 | SubclassOfB2] list[SubclassOfB1 | SubclassOfB2] . list[SubclassOfB1 | SubclassOfB2] How can I do this?我怎样才能做到这一点?

You linked a post that essentially addresses the issue, but you seem to still be confused:你链接了一篇基本上解决了这个问题的帖子,但你似乎仍然感到困惑:

InheritsB1 is a subclass of B , so list[InheritsB1] is always a list of B . InheritsB1B的子类,因此list[InheritsB1]始终是B的列表。

This is not true.这不是真的。 To quote fromthis section of PEP 484:引用 PEP 484 的这一部分

By default generic types are considered invariant in all type variables默认情况下,泛型类型在所有类型变量中都被认为是不变

The theorysection on variance in PEP 483 attempts to explain the concepts in much greater detail. PEP 483 中关于方差的理论部分试图更详细地解释这些概念。 I suggest you read through PEP 483 as well as PEP 484, if you want to get more serious about type safety.如果你想更认真地了解类型安全,我建议你通读 PEP 483 和 PEP 484。

The mypy complaint is justified and unless you want to follow the tip provided by mypy and change the type to something covariant like Sequence instead, you will have to work a bit more with generics yourself. mypy的抱怨是有道理的,除非您想按照mypy提供的提示将类型更改为像Sequence这样的协变类型,否则您将不得不自己对 generics 做更多的工作。


How best to solve your particular conundrum depends on other factors around your classes that are still ambiguous in your original post.如何最好地解决您的特定难题取决于您的课程周围的其他因素,这些因素在您的原始帖子中仍然模棱两可。

But one option might be to make A generic in terms of a type variable that has an upper bound of B .但一种选择可能是根据具有B上限的类型变量使A 通用 Then, if you want to define a subclass of A to hold elements of a specific subtype of B , there would be no problem:然后,如果你想定义一个A的子类来保存B特定子类型的元素,就不会有问题:

from typing import Generic, TypeVar


_BType = TypeVar("_BType", bound="B")


class B:
    pass


class SubB(B):
    pass


class A(Generic[_BType]):
    attribute: list[_BType]


class SubA(A[SubB]):
    # attribute: list[SubB]
    ...


reveal_type(SubA().attribute)  # Revealed type is "builtins.list[SubB]"

Note that in this setup, you don't even have to override/annotate SubA.attribute (which is why I commented it out) because you specify the type argument for A to be SubB during inheritance, which means that SubA is no longer generic and attribute will always be inferred as list[SubB] .请注意,在此设置中,您甚至不必覆盖/注释SubA.attribute (这就是我将其注释掉的原因),因为您在SubB期间将A的类型参数指定为 SubB,这意味着SubA不再是通用的和attribute将始终被推断为list[SubB]

The code is type safe (passes mypy --strict ), but it still may or may not be practical for you, depending on what other requirements you have for the classes involved.该代码是类型安全的(通过mypy --strict ),但它对您来说仍然可能实用,也可能不实用,具体取决于您对所涉及的类的其他要求。 If you provide more details, I can try to amend my answer to better suit your setup.如果您提供更多详细信息,我可以尝试修改我的答案以更好地适应您的设置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM