Этот код действительно полон ошибок.Просто подумав о потоке этого __getattribute__
метода: учитывая имя атрибута, мы ищем атрибут в классе-оболочке (вызывая реализацию суперкласса).Если атрибут там не найден - чего нет в случае с «fib», потому что он находится в обернутом классе, а не в обертке - Python вызовет AttributeError.Хорошо, мы поймали это, предположительно, чтобы мы могли продолжить поиск в обернутом классе.Но что мы делаем в исключении?Ничего такого.По какой-то причине код содержится в предложении else, которое вызывается только тогда, когда исключение было не возбуждено.
Так что если мы исправим это, удалив pass
и переместив код изблок else
, что тогда?Что ж, теперь нужно получить self.inst
, то есть экземпляр обернутого класса.Но угадайте, что, получение атрибута вызовет метод __getattribute__
.Итак, мы возвращаемся.Теперь исходный вызов для получения атрибута inst
будет успешным.Мы присваиваем его x
.Что теперь?Ээ, ничего.Выходим без возврата х.Таким образом, исходный вызов получает None для значения self.inst
и пытается вызвать __getattribute__
для этого - поэтому мы получим еще один AttributeError.
Откровенно говоря, этот код выглядит так, как будто он был написан кем-токоторый не очень хорошо знает Python. можно было бы исправить это, в дополнение к вышеуказанному изменению, возвращая значение вызова суперкласса вместо его присвоения:
def __getattribute__(self, s):
try:
return super(ProfiledClass, self).__getattribute__(s)
except AttributeError:
x = self.inst.__getattribute__(s)
if type(x) == type(self.__init__):
return profiling_decorator(x)
else:
return x
, но это все еще довольно плохой код,Для начала, вы никогда не должны вызывать методы двойного подчеркивания напрямую, поэтому строка после исключения должна быть x = getattr(self.inst, s)
.Но проблемы глубже этого;__getattribute__
- совершенно неправильный метод для переопределения.Этот метод вызывается для всех поисков атрибутов, отсюда и сложный try / super / кроме вещей.Но Python дает вам метод, который вызывается только тогда, когда атрибут не напрямую найден, то есть __getattr__
.Определение этого позволит вам полностью удалить большую часть кода:
def __getattr__(self, s):
x = getattr(self.inst, s)
if type(x) == type(self.__init__):
return profiling_decorator(x)
else:
return x
(И если бы я был действительно разборчив, я бы заменил этот type(x) == type(self.__init__)
материал просто if callable(x)
.)
И последняя ошибка в этом коде состоит в том, что они оставили factorial
явно оформленными, когда весь смысл кода в том, что методы будут оформлены автоматически.