'How can I access to __annotations__ of parent class?
Is there any way to access to the typing __annotations __ of the parent class?
In the above example, the class Student
inherit from class Person
, but It does not contains the typing annotations from the Person
class.
class Person:
name: str
address: str
def __init__(self):
print(self.__annotations__)
class Student(Person):
year: int
person = Person()
# {'name': <class 'str'>, 'address': <class 'str'>}
student = Student()
# {'year': <class 'int'>}
# HERE I would expect the name and the address props
Solution 1:[1]
self.__annotations__
, in the absence of an instance attribute named __annotations__
, is equivalent to type(self).__annotations__
. Since Student.__annotations__
is defined, there is no reason to look for Person.__annotations__
. You would need to check each class in your MRO. The easiest way to do that is to define a single class method in some base class (or make it an external function that isn't associated with any single class).
class Person:
name: str
address: str
@classmethod
def get_annotations(cls):
d = {}
for c in cls.mro():
try:
d.update(**c.__annotations__)
except AttributeError:
# object, at least, has no __annotations__ attribute.
pass
return d
def __init__(self):
print(self.get_annotations())
class Student(Person):
year: int
Solution 2:[2]
Here's the answer I would have liked to have seen when a Google search brought me here.
from collections import ChainMap
def all_annotations(cls) -> ChainMap:
"""Returns a dictionary-like ChainMap that includes annotations for all
attributes defined in cls or inherited from superclasses."""
return ChainMap(*(c.__annotations__ for c in cls.__mro__ if '__annotations__' in c.__dict__) )
Unlike @chepner's approach, this correctly handles cases where multiple superclasses provide different annotations for the same attribute name (which is often inadvisable, but can be fine, e.g. when a subclass gives an attribute with a more specific annotation). @chepner's approach will give priority to the annotation that occurs last in the method resolution order (MRO), whereas Python's class inheritance generally gives priority to whichever class comes first in that order. (If you did want to use @chepner's approach, you'd probably do better to update annotations in the reverse of the MRO, taking care not to accidentally lose track of any annotations defined in this class.)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | chepner |
Solution 2 |