admin管理员组

文章数量:1313163

I posted a question earlier asking how to overload Python methods using generics.

The solution provided is shown below.

from __future__ import annotations
from typing import Literal, overload

class WoodData: ...
class ConcreteData: ...

class Foo[T: Literal["wood", "concrete"]]:
    def __init__(self, data_type: T) -> None:
        self.data_type = data_type

    @overload
    def get_data(self: Foo[Literal["wood"]]) -> WoodData: ...

    @overload
    def get_data(self: Foo[Literal["concrete"]]) -> ConcreteData: ...

    def get_data(self):
        if self.data_type == "wood":
            return WoodData()
        return ConcreteData()

foo = Foo("concrete")
x = foo.get_data()

This example works as expected, but the problem arises when we try to call get_data from a sibling class method.

For example, I add the bar method below.

from __future__ import annotations
from typing import Literal, overload

class WoodData: ...
class ConcreteData: ...

class Foo[T: Literal["wood", "concrete"]]:
    def __init__(self, data_type: T) -> None:
        self.data_type = data_type

    @overload
    def get_data(self: Foo[Literal["wood"]]) -> WoodData: ...

    @overload
    def get_data(self: Foo[Literal["concrete"]]) -> ConcreteData: ...

    def get_data(self):
        if self.data_type == "wood":
            return WoodData()
        return ConcreteData()
    
    def bar(self):
        self.get_data()

This gives the typing error:

Cannot access attribute "get_data" for class "Foo[T@Foo]*"
  Could not bind method "get_data" because "Self@Foo[T@Foo]" is not assignable to parameter "self"
    "Foo[T@Foo]*" is not assignable to "Foo[Literal['wood']]"
      Type parameter "T@Foo" is covariant, but "T@Foo" is not a subtype of "Literal['wood']"
        Type "Literal['wood', 'concrete']" is not assignable to type "Literal['wood']"
          "Literal['concrete']" is not assignable to type "Literal['wood']"
  Could not bind method "get_data" because "Self@Foo[T@Foo]" is not assignable to parameter "self"
    "Foo[T@Foo]*" is not assignable to "Foo[Literal['concrete']]"
      Type parameter "T@Foo" is covariant, but "T@Foo" is not a subtype of "Literal['concrete']"

How can I access the get_data function from another method without getting a typing error?

I posted a question earlier asking how to overload Python methods using generics.

The solution provided is shown below.

from __future__ import annotations
from typing import Literal, overload

class WoodData: ...
class ConcreteData: ...

class Foo[T: Literal["wood", "concrete"]]:
    def __init__(self, data_type: T) -> None:
        self.data_type = data_type

    @overload
    def get_data(self: Foo[Literal["wood"]]) -> WoodData: ...

    @overload
    def get_data(self: Foo[Literal["concrete"]]) -> ConcreteData: ...

    def get_data(self):
        if self.data_type == "wood":
            return WoodData()
        return ConcreteData()

foo = Foo("concrete")
x = foo.get_data()

This example works as expected, but the problem arises when we try to call get_data from a sibling class method.

For example, I add the bar method below.

from __future__ import annotations
from typing import Literal, overload

class WoodData: ...
class ConcreteData: ...

class Foo[T: Literal["wood", "concrete"]]:
    def __init__(self, data_type: T) -> None:
        self.data_type = data_type

    @overload
    def get_data(self: Foo[Literal["wood"]]) -> WoodData: ...

    @overload
    def get_data(self: Foo[Literal["concrete"]]) -> ConcreteData: ...

    def get_data(self):
        if self.data_type == "wood":
            return WoodData()
        return ConcreteData()
    
    def bar(self):
        self.get_data()

This gives the typing error:

Cannot access attribute "get_data" for class "Foo[T@Foo]*"
  Could not bind method "get_data" because "Self@Foo[T@Foo]" is not assignable to parameter "self"
    "Foo[T@Foo]*" is not assignable to "Foo[Literal['wood']]"
      Type parameter "T@Foo" is covariant, but "T@Foo" is not a subtype of "Literal['wood']"
        Type "Literal['wood', 'concrete']" is not assignable to type "Literal['wood']"
          "Literal['concrete']" is not assignable to type "Literal['wood']"
  Could not bind method "get_data" because "Self@Foo[T@Foo]" is not assignable to parameter "self"
    "Foo[T@Foo]*" is not assignable to "Foo[Literal['concrete']]"
      Type parameter "T@Foo" is covariant, but "T@Foo" is not a subtype of "Literal['concrete']"

How can I access the get_data function from another method without getting a typing error?

Share Improve this question asked Jan 31 at 0:10 MattMatt 1,6325 gold badges31 silver badges62 bronze badges 4
  • 1 I mentioned this problem at your previous question. This comment right next to it should help. – InSync Commented Jan 31 at 2:30
  • I did see that comment, but I don't understand what it means to be honest. I'll look into bound + typing constraints I guess – Matt Commented Jan 31 at 15:51
  • 1 You are already using a bound instead of constraints (i.e., T: Literal["wood", "concrete"] rather than T: (Literal["wood"], Literal["concrete"])). The comment suggests adding a third overload: @overload def get_data(self) -> WoodData | ConcreteData: .... – InSync Commented Jan 31 at 16:09
  • Ahhhh, now that makes it all make sense. Thank you. – Matt Commented Jan 31 at 16:11
Add a comment  | 

1 Answer 1

Reset to default 1

As @InSync mentioned in the comments we can solve this by adding a third overload.

from __future__ import annotations
from typing import Literal, overload

class WoodData: ...
class ConcreteData: ...

class Foo[T: Literal["wood", "concrete"]]:
    def __init__(self, data_type: T) -> None:
        self.data_type = data_type

    @overload
    def get_data(self: Foo[Literal["wood"]]) -> WoodData: ...

    @overload
    def get_data(self: Foo[Literal["concrete"]]) -> ConcreteData: ...

    @overload
    def get_data(self) -> WooData | ConcreteData: ...


    def get_data(self):
        if self.data_type == "wood":
            return WoodData()
        return ConcreteData()
    
    def bar(self):
        self.get_data()

本文标签: pythonOverloaded method invocation causes type check errorStack Overflow