Зачем атрибуту класса устанавливать значение, а печатать тип 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)
Тогда проанализируй и постарайся понять свою ошибку:)