You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A dataclass with generic field does not infer the generics type when a default is provided.
To Reproduce
@dataclass
class Data(Generic[T]):
field: T = 1
# -> "Incompatible types in assignment (expression has type "int", variable has type "T")" (INCORRECT, should be accepted w/o error)
reveal_type( Data(17.5).field )
# -> Revealed type is "builtins.float*" (CORRECT)
reveal_type( Data().field )
# -> Revealed type is "<nothing>" (FAILED, should be int)
Expected Behavior
The default value supplied in the dataclass should be honored. Semantically the construct is not an assignment, but a default value
in the __init__ function:
Under the hood the (autogenerated) dataclass constructor looks like this
def __init__(self, field = 1):
self.field = field
So when field is not provided during construction of Data instance the field is passed as an int, so the generic type T should be inferred as int (if field is omitted in constructor). In the exactly same way as T is inferred as float when the field is given explicitly in the constructor (e.g. Data(17.5).field)
Concluding, what should happen:
Data() -> infer T as int (from the default in dataclass) (does not work)
Data(val) -> infer T as same type as val (this works)
Actual Behavior
Default argument is ignored
Your Environment
Mypy version used: 0.960
Mypy command-line flags:
Mypy configuration options from mypy.ini (and other config files):
Python version used: 3.9.7
Operating system and version: Windows 10
The text was updated successfully, but these errors were encountered:
I would not expect this to work. A dataclass decorator effectively adds a synthesized __init__ method to the class. For your sample, that method would look like the following:
def__init__(self, field: T=1) ->None: ...
If you were to explicitly create a generic class with this __init__ method, mypy would similarly reject it because concrete default argument values are not supported for generic parameters.
I see. So the real issue is that concrete default arguments are not allowed for generic parameters. However, after looking around on this site I found that this feature seems to meet some interest and has been requested several times so far (#4236, #3737, #10854, #10504, #5802, #5273, #5464, and perhaps more)
The issue is that the proposed workaround or solution with @overload (as in #4236 (comment)) does not work for dataclasses (or at least I cannot see how this would work in my case). With dataclasses the __init__ is autogenerated and manually overwriting __init__would undermine the purpose of using dataclasses in the first place.
The things is that when writing code with generics one arrives quickly at the point where the built-in default (T=Any) is not adequate.
Bug Report
A dataclass with generic field does not infer the generics type when a default is provided.
To Reproduce
Expected Behavior
The default value supplied in the dataclass should be honored. Semantically the construct is not an assignment, but a default value
in the
__init__
function:Under the hood the (autogenerated) dataclass constructor looks like this
So when
field
is not provided during construction ofData
instance the field is passed as anint
, so the generic typeT
should be inferred asint
(if field is omitted in constructor). In the exactly same way as T is inferred asfloat
when the field is given explicitly in the constructor (e.g.Data(17.5).field
)Concluding, what should happen:
Data()
-> infer T as int (from the default in dataclass) (does not work)Data(val)
-> infer T as same type asval
(this works)Actual Behavior
Default argument is ignored
Your Environment
mypy.ini
(and other config files):The text was updated successfully, but these errors were encountered: