tamuhey
tamuhey

Reputation: 3535

How to annotate the type of field in dataclass to be different from the type of its __init__?

I created a dataclass Foo, which accepts any type that can be converted to int:

import dataclasses


@dataclasses.dataclass
class Foo:
    a: int

    def __post_init__(self):
        # Here `self.a` is converted to int, so this class accepts any type that can be converted to int
        self.a = int(self.a)


# mypy error: Argument 1 to "Foo" has incompatible type "str"; expected "int",
foo = Foo("1")
print(foo)
print(foo.a + 2)

Output:

Foo(a=1)
3

However, mypy reports the below error:

error: Argument 1 to "Foo" has incompatible type "str"; expected "int"

If I fix the type of Foo.a to Union[str, int], mypy reports another error:

error: Unsupported operand types for + ("str" and "int")

How to write a dataclass whose type of the field and the init argument are different?

Upvotes: 6

Views: 1697

Answers (1)

user2357112
user2357112

Reputation: 281843

You want to decouple the a field from the a argument that __init__ takes. This would essentially require both an

a: InitVar[Union[SupportsInt, str]]

and an

a: int = field(init=False)

one to describe the __init__ argument, and one to describe the field. You can't do that, though. An InitVar and a field can't have the same name.

Your best option is to not use a dataclass, but if you're absolutely determined to do things that way, you'll have to write your own __init__:

@dataclasses.dataclass
class Foo:
    a: int
    
    def __init__(self, a: typing.Union[typing.SupportsInt, str]):
        self.a = int(a)

Upvotes: 5

Related Questions