Распечатайте аргументы и значения функции в методе __getattribute__

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

Я использую метод getattribute для реализации этого, мой код ниже

    def __getattribute__(self, attr):

        def newfunc(*args, **kwargs):

            print( "%r Calling %r with %r %r" % (self, attr, args, kwargs))


    return newfunc 

Код выводит имя функции и аргументы, но исходный метод не выполняется, так как он возвращает новую функцию вместо вызова старой.

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

Мой вопрос. есть ли способ распечатать имя и аргументы функции внутри __getattribute__method ?

или есть способ распечатать имя и аргументы функции каждый раз, когда экземпляр вызывает свой метод?


Пс. кроме использования декораторов, я знал, что могу использовать декоратор для этого, но я не хочу помещать декоратор перед каждым методом, который я использую


person whtitefall    schedule 16.10.2019    source источник


Ответы (2)


Основная и очевидная проблема с вашим кодом заключается в том, что вы ни в коем случае не извлекаете исходный атрибут в экземпляре, что является работой __getattribute__ - нарушение __getattribute__ - это 100% мертвый способ заставить ваш класс вообще не работать.

Итак, первое, что нужно сделать, это вызвать рабочий __getattribute__ в суперклассе для получения атрибута.

Затем вторая часть, которой явно не хватает в вашем коде, заключается в том, что вы даже не пытаетесь вызвать исходную функцию или метод из вашей функции «принтера». Ставим такой вызов в конец его кода.

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

После того, как вы позаботитесь об этих 3 пунктах, все должно работать так, как вы задумали:

def __getattribute__(self, attr):

    original = super().__getattribute__(attr)
    if callable(original):
        def newfunc(*args,  **kwargs):

            print( "%r Calling %r with %r %r" % (self, attr, args, kwargs))
            return original(*args, **kwargs)
        return newfunc
    return original

person jsbueno    schedule 16.10.2019
comment
Спасибо ! это работает для меня, я действительно пытался вызвать функцию с помощью getattr, но это не сработало - person whtitefall; 16.10.2019
comment
__getattr__ вызывается только для атрибутов, которых нет в экземпляре — его цель — предоставить динамические атрибуты, которые предоставляет только он. Напротив, __getattribute__ вызывается для доступа к каждому атрибуту. (и сам __getattr__ вызывается внутри object.__getattribute__ как часть поиска атрибута, а не после его возврата) - person jsbueno; 16.10.2019

Так как вы не хотите применять декоратор, но вам нужно "распечатать имя функции и аргументы внутри метода __getattribute__", используйте следующий подход:

Чтобы избежать бесконечной рекурсии в методе __getattribute__, его реализация всегда должна вызывать метод базового класса с тем же именем для доступа к любым необходимым атрибутам.

class A:
    def my_func(self, a, b):
        return a + b

    def __getattribute__(self, attr):
        def newfunc(*args, **kwargs):
            print("%r Calling %r with %r %r" % (self, attr, args, kwargs))

            return object.__getattribute__(self, attr)
        return newfunc

a = A()
a.my_func(1, 2)
a.my_func(3, 4)

Пример вывода:

<__main__.A object at 0x116861710> Calling 'my_func' with (1, 2) {}
<__main__.A object at 0x116861710> Calling 'my_func' with (3, 4) {}
person RomanPerekhrest    schedule 16.10.2019