11

I want to get the type hints for an object's attributes. I can only get the hints for the class and not an instance of it.

I have tried using foo_instance.__class__ from here but that only shows the class variables.

So in the example how do I get the type hint of bar?

class foo:
    var: int = 42
    def __init__(self):
        self.bar: int = 2

print(get_type_hints(foo)) # returns {'var': <class 'int'>}
martineau
  • 119,623
  • 25
  • 170
  • 301
ellie ff1493
  • 194
  • 2
  • 13

4 Answers4

6

I just had the same problem. The python doc isn't that clear since the example is made with what is now officially called dataclass.

Student(NamedTuple):
    name: Annotated[str, 'some marker']

get_type_hints(Student) == {'name': str}
get_type_hints(Student, include_extras=False) == {'name': str}
get_type_hints(Student, include_extras=True) == {
    'name': Annotated[str, 'some marker']
}

It give the impression that get_type_hints() works on class directly. Turns out get_type_hints() returns hints based on functions, not on class. That way it can be use with both if we know that. A normal class obviously not being instantiated at it's declaration, it does not have any of the variables set within the __init__() method who hasn't yet been called. It couldn't be that way either if we want the possibility to get the type hints from class-wide variables.

So you could either call it on __init__(), that is if variables are passed in arguments though (yes i seen it's not in your example but might help others since i didn't seen this anywhere in hours of search);

class foo:
    var: int = 42
    def __init__(self, bar: int = 2):
        self.bar = int

print(get_type_hints(foo.__init__))

At last for your exact example i believe you have two choices. You could instantiate a temporary object and use del to clean it right after if your logic allows it. Or declare your variables as class ones with or without default values so you can get them with get_type_hints() and assign them later in instantiations.

Carl L.D.
  • 89
  • 1
  • 6
4

Maybe this is a hack, and you have to be the creator of your instances, but there are a subset of cases in which using a data class will get you what you want;

Python 3.7+

@dataclass
class Foo:
    bar: str = 2

if __name__ == '__main__':
    f = Foo()
    print(f.bar)
    print(get_type_hints(f))

2
{'bar': <class 'str'>}
SteveJ
  • 3,034
  • 2
  • 27
  • 47
1

Hints only exist at the class level — by the time an instance is created the type of its attributes will be that of whatever value has been assigned to them. You can get the type of any instance attribute by using the first form of the built-in type() function — e.g. type(foo_instance.var).

martineau
  • 119,623
  • 25
  • 170
  • 301
  • the type function returns the type, not the type hint. this must be possible in some way because pycharm shows the type hint (not the type) of the attribute if accessed – ellie ff1493 Jul 04 '20 at 00:11
  • It must be using the object's `__class__` along with the attribute's name to show it. – martineau Jul 04 '20 at 00:14
  • Type hints are stored in a class' `__annotations__` attribute as described in @Remco Haszing answer to the linked question — since it's a dictionary. you could look the attribute's name up in that. – martineau Jul 04 '20 at 00:22
  • __class__ will only work with the class variable and if it did work with type() it will only show the type of the contents of the variable and not the type-hint, pycharm correctly shows the type hint if a different type is assigned to the attribute – ellie ff1493 Jul 04 '20 at 00:23
  • the `__annotations__` only stores class variables and does not store the attributes type hints, its the same as `get_type_hints` and does not contain `bar` – ellie ff1493 Jul 04 '20 at 00:26
  • 1
    Annotations are stored at module or class-level, so can be found in the `__annotations__` attribute of an object's `__class__`, however annotations at function level are not evaluated and not stored (see last sentence of [Runtime Effects of Type Annotations](https://www.python.org/dev/peps/pep-0526/#runtime-effects-of-type-annotations)). I believe this means that the information you want simply isn't available anywhere except in the source code. – martineau Jul 04 '20 at 17:28
  • thanks, that answers my question @martineau i made it a post along with information on how to get that information along with a disclaimer that its probably a bad idea – ellie ff1493 Jul 05 '20 at 01:14
  • i will in 20 hours when it lets me – ellie ff1493 Jul 05 '20 at 03:26
1

This information isn't evaluated and only exists in the source code. if you must get this information, you can use the ast module and extract the information from the source code yourself, if you have access to the source code.

You should also ask yourself if you need this information because in most cases reevaluating the source code will be to much effort.

ellie ff1493
  • 194
  • 2
  • 13