class GetAttr:
    attr1 = 1
    def __init__(self):
        self.attr2 = 2
    def __getattr__(self, attr):            # Tylko dla niezdefiniowanych atrybutów
        print('pobieranie:', attr)                 # Nie attr1: dziedziczony z klasy
        if attr == 'attr3':                 # Nie attr2: przechowany w instancji
            return 3
        else:
            raise AttributeError(attr)

X = GetAttr()
print(X.attr1)
print(X.attr2)
print(X.attr3)
print('-'*20)

class GetAttribute:
    attr1 = 1
    def __init__(self):
        self.attr2 = 2
    def __getattribute__(self, attr):       # Dla pobrań wszystkich atrybutów
        print('pobieranie:',  attr)                # Tutaj użycie klasy nadrzędnej w celu uniknięcia pętli
        if attr == 'attr3':
            return 3
        else:
            return object.__getattribute__(self, attr)

X = GetAttribute()
print(X.attr1)
print(X.attr2)
print(X.attr3)

