What is the best way to look up the class from annotations if using py3.10 from __future__ import annotations
? Previously, self.__annotations__[name]
would get you an object but now it returns a string. You can use globals()
as shown but that just doesn't seem right to me. Is there a better way?
@dataclass
class Person:
height: float
def stack(self, other: Person):
return Person(self.height + other.height) #gymnasts
@dataclass
class Chair:
height: float
def stack(self, other: Chair):
return Chair(0.6*(self.height + other.height) ) #stackable chairs
@dataclass
class Room:
person: Person
chair: Chair
def set(self, name: str, val: float):
# lots of complicated validation
# factory = self.__annotations__[name] # this worked before from __future__ import annotations
factory = globals()[self.__annotations__[name]]
self.__setattr__(name, factory(height=val))
Use typing.get_type_hints
to access the evaluated __annotations__
of a "function, method, module or class object". Notably, this is aware of basic inheritance – it merges inherited annotations and uses globals
of the current class instead of the method's module.
@dataclass
class Room:
person: Person
chair: Chair
def set(self, name: str, val: float):
factory = get_type_hints(type(self))[name]
self.__setattr__(name, factory(height=val))
While typing.get_type_hints
does some additional work over just inspecting globals
, __future__.annotations
inherently erases non-global information. For the uncommon case of classes defined in a locals
scope one has to explicitly provide the namespace.