'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