Профилирование всех методов класса - PullRequest
0 голосов
/ 29 ноября 2018

Я читаю Практические шаблоны проектирования Python и пытаюсь изучить концепцию декоратора.Я застрял в последнем примере, где я не могу получить логику написания профилировщика, который применяется ко всем методам класса.

Вот пример из книги .Я не переписывал это здесь из-за ограничения копирайта, но я надеюсь, что ссылка на Книгу Google достаточна.

Проблема в том, что когда я реализую код и применяю его в своем классе DoMathStuff, я получаю TypeError: 'NoneType' object is not callable.Для меня часть try/except/else неясна, и я думаю, что где-то есть опечатка, но я могу сказать, где.

@profile_all_class_methods
class DoMathStuff(object):
    """docstring for DoMathStuff"""
    def __init__(self, n):
        self.n = n

    def fib(self):
        fPrev, f = 1, 1
        for num in xrange(2, self.n):
            fPrev, f = f, f + fPrev

        return f

    @profiling_decorator
    def fact(self):
        fct = 1
        for num in xrange(1, self.n):
            fct *= num

        return fct


if __name__ == '__main__':
    m = DoMathStuff(10)
    print("Fib = {}, Fact = {}".format(m.fib(), m.fact()))

Редактировать: И вот ошибка, которую я получаю

Traceback (most recent call last):
  File "class_profiler.py", line 62, in <module>
    print("Fib = {}, Fact = {}".format(m.fib(), m.fact()))
TypeError: 'NoneType' object is not callable

1 Ответ

0 голосов
/ 29 ноября 2018

Этот код действительно полон ошибок.Просто подумав о потоке этого __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 явно оформленными, когда весь смысл кода в том, что методы будут оформлены автоматически.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...