Issue43257
Created on 2021-02-18 18:53 by xirdneh, last changed 2021-02-20 01:18 by gvanrossum.
Messages (4) | |||
---|---|---|---|
msg387266 - (view) | Author: Josue Balandrano Coronel (xirdneh) | Date: 2021-02-18 18:53 | |
Using typing.get_type_hints() on classes returns the wrong value when a class variable has the same name as a type and a default value. For instance: from dataclasses import dataclass from typing import get_type_hints @dataclass class DataClassHints: str: str="asdf" >>> get_type_hints(DataClassHints) ... NameError: name 'asdf' is not defined Looks like get_type_hints() is using "asdf" as a type. This is more clear if we use something like datetime: from datetime import datetime class ClassHints: datetime: datetime=datetime.now() >>> get_type_hints(ClassHints) ... {'datetime': datetime.datetime(2021, 2, 18, 12, 40, 16, 966502) If we do the same thing in a method get_type_hints works correctly: class CorrectHints: def __init__(self, str: str="asdf", datetime: datetime=datetime.now()): self.str = str self.datetime = datetime >>> ch = CorrectHints() >>> ch.str ... 'asdf' >>> ch.datetime ... datetime.datetime(2021, 2, 18, 12, 41, 46, 214844) >>> get_type_hints(CorrectHints.__init__) ... {'str': str, 'datetime': datetime.datetime} Also functions work correctly: def func_type_hints(str: str="asdf", datetime: datetime=datetime.now()): return f"str: {str}, datetime: {datetime}" >>> func_type_hints() ... 'str: asdf, datetime: 2021-02-18 12:44:21.102933' >>> get_type_hints(func_type_hints) ... {'str': str, 'datetime': datetime.datetime} It looks like get_type_hints is evaluating the default value in a class variable before the type hint. Here's another way to replicate this issue to make it clearer: class EvalOrderHints: datetime = datetime.now() datetime: datetime >>> get_type_hints(EvalOrderHints) ... {'datetime': datetime.datetime(2021, 2, 18, 12, 47, 56, 608261)} >>> EvalOrderHints().datetime ... datetime.datetime(2021, 2, 18, 12, 47, 56, 608261) |
|||
msg387328 - (view) | Author: Ken Jin (kj) * | Date: 2021-02-19 15:00 | |
Hmm I noticed this occurs in Python 3.9 but not 3.10. If you insert ``from __future__ import annotations`` at the start of your code, it stops erroring. Anyways, I don't think this is dataclass specific, the following code using a plain class also errors: ``` from typing import get_type_hints class T: str: str = 'a' get_type_hints(T) # Error. ``` Inspecting __annotations__ tells us why: >>> T.__annotations__ {'str': 'a'} You can see that the annotations are wrong. Meanwhile with from __future__ import annotations: >>> T.__annotations__ {'str': 'str'} Seeing that SETUP_ANNOTATIONS in ceval.c didn't change, I suspect it's compiler related. |
|||
msg387331 - (view) | Author: Guido van Rossum (gvanrossum) * ![]() |
Date: 2021-02-19 15:44 | |
Sure looks like a compiler bug! Can you investigate whether this occurs in earlier Python versions? Maybe bisect if it doesn’t? |
|||
msg387379 - (view) | Author: Guido van Rossum (gvanrossum) * ![]() |
Date: 2021-02-20 01:18 | |
Oops, I realized it's not really a compiler bug. When the compiler sees class C: str: str = "abc" if effectively rearranges that to class C: str = "abc" __annotations__["str"] = str (where __annotations__ is initialized to {} at the start of the class scope). This goes to prove once again that silly things like str: str are an anti-pattern and should not be used. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2021-02-20 01:18:52 | gvanrossum | set | messages: + msg387379 |
2021-02-19 15:44:01 | gvanrossum | set | messages: + msg387331 |
2021-02-19 15:00:25 | kj | set | nosy:
+ gvanrossum, kj messages: + msg387328 |
2021-02-18 21:57:14 | eric.smith | set | nosy:
+ eric.smith |
2021-02-18 18:53:09 | xirdneh | create |