Зачем атрибуту класса устанавливать значение, а печатать тип None?

Вот код:

class Animal:
    def __init__(self, animal_type):
        self.animal_type = animal_type

class Cat(Animal):
    def __init__(self, animal_type, favorite_food):
        super().__init__(animal_type)
        self.favorite_food = favorite_food

    def cat_print(self):
        print("{}'s favorite food is {}.".format(self.animal_type, self.favorite_food))

    def __getattribute__(self, item):
        print('__getattribute__() be called. Item is: ', item)

    def __getattr__(self, item):
        print('__getattr__() be called. Item is: ', item)

    def __setattr__(self, key, value):
        print('__setattr__() be called. key and Value is: ', key, value)


cat = Cat('cat', 'fish')
print(cat.animal_type)
print(cat.favorite_food)

Когда я печатаю cat.animal_typeНапечатай Нет. Я думаю, что из-за я переписать метод: __setattr__() а также __getattribute__(), Значение не может перейти в атрибут.

Я хочу знать, как происходит процесс присвоения атрибута и получения атрибута в классе в Python?

Благодарю.

2 ответа

Решение

Причина, по которой все ваши атрибуты None даже несуществующие атрибуты, такие как favorite, это:

def __getattribute__(self, item):
    print('__getattribute__() be called. Item is: ', item)

Вы переопределяете нормальный object.__getattribute__ код с методом, который всегда возвращает None, Если вы хотите, чтобы он что-то печатал, а также делал обычные вещи, вы должны сделать это явно, используя super - так же, как вы уже сделали в своем инициализаторе:

def __getattribute__(self, item):
    print('__getattribute__() be called. Item is: ', item)
    return super().__getattribute__(item)

Если вы это исправите, поиск существующих атрибутов теперь будет работать, но несуществующие атрибуты все равно будут возвращаться None вместо того, чтобы поднять AttributeError, Зачем?

def __getattr__(self, item):
    print('__getattr__() be called. Item is: ', item)

Нормальный object.__getattribute__ (что вы сейчас правильно вызываете) ищет атрибут в объекте __dict__ и в своем классе и во всех его предках (с некоторой дополнительной сложностью, связанной с дескрипторами, которые я собираюсь игнорировать здесь), и затем, если ничего не найдено (или что-то найдено, но выборка вызывает AttributeError), это вызывает класс __getattr__, И вы предоставляете __getattr__ это возвращает None,

Здесь вы снова хотите делегировать суперклассам:

def __getattr__(self, item):
    print('__getattr__() be called. Item is: ', item)
    return super().__getattr__(item)

За исключением того, что нет реализации по умолчанию __getattr__, Итак, вы получите AttributeError, но это будет о super не имея __getattr__ не о Cat не имея favorite,

Если вы знаете, что один из ваших базовых классов хочет предоставить __getattr__ для вас, чтобы делегировать, super к этому. Но если вы знаете, никто не делает:

def __getattr__(self, item):
    print('__getattr__() be called. Item is: ', item)
    raise AttributeError(item)

И если вы понятия не имеете (потому что, скажем, ваш класс был разработан для использования в качестве смеси с чужой иерархией классов), вы, вероятно, захотите что-то вроде этого:

def __getattr__(self, item):
    print('__getattr__() be called. Item is: ', item)
    try:
        ga = super().__getattr__
    except AttributeError:
        pass
    else:
        return ga(item)
    raise AttributeError(item)

Если вы исправите оба из них, теперь вы получите AttributeError на атрибуты, которые вы установили. Зачем?

def __setattr__(self, key, value):
    print('__setattr__() be called. key and Value is: ', key, value)

Та же проблема. Здесь вы можете установить атрибут явно, например так:

def __setattr__(self, key, value):
    print('__setattr__() be called. key and Value is: ', key, value)
    super().__getattribute__('__dict__')[key] = value

... или вы можете просто захотеть делегировать снова:

def __setattr__(self, key, value):
    print('__setattr__() be called. key and Value is: ', key, value)
    super().__setattr__(key, value)

Добавьте это в init в классе Cat:

self.animal_type = animal_type

И измените свой принт

print(cat.favorite)

в

print(cat.favorite_food)

Тогда проанализируй и постарайся понять свою ошибку:)

Другие вопросы по тегам