Лучший способ записывать вызовы методов в Python?

Мы можем закодировать какой-то декодер ведения журнала для вызовов эхо-функций/методов, например:

def log(fn):
    ...

@log
def foo():
    ...

class Foo(object):
    @log
    def foo(self):
        ...

    @log
    def bar(self, a, b):
        ...

    @log
    def foobar(self, x, y, z):
        ...

Но что, если нам нравится записывать вызовы методов, не помещая это много @log перед каждым определением meth? Есть ли способ просто поставить один декоратор над определением класса, чтобы все его вызовы методов были украшены/записаны? Или есть некоторые другие интересные и интересные способы сделать это вместо декоратора?

Ответы

Ответ 1

См. Прикрепление декоратора ко всем функциям класса

Однако, как указывает принятый ответ на этот вопрос, обычно это не очень хорошая идея.

Если вы решите перейти на аспект ориентированный маршрут программирования, я предлагаю начать здесь: Любая библиотека поддержки AOP для Python?

Ответ 2

Это может быть излишним, но есть функция функции трассировки, которая сообщит вам о большой активности в вашей программе:

import sys

def trace(frame, event, arg):
    if event == "call":
        filename = frame.f_code.co_filename
        if filename == "path/to/myfile.py":
            lineno = frame.f_lineno
            # Here I'm printing the file and line number, 
            # but you can examine the frame, locals, etc too.
            print "%s @ %s" % (filename, lineno)
    return trace

sys.settrace(trace)
call_my_function()
sys.settrace(None)

Ответ 3

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

Итак, вот пример, который может сделать то, что вы хотите, но без декоратора:

#!/usr/bin/env python
import inspect


class Foo(object):

    def foo(self):
        pass

    def bar(self, a, b):
        pass

    def foobar(self, x, y, z):
        pass

    def __getattribute__(self, name):
        returned = object.__getattribute__(self, name)
        if inspect.isfunction(returned) or inspect.ismethod(returned):
            print 'called ', returned.__name__
        return returned


if __name__ == '__main__':
    a = Foo()
    a.foo()
    a.bar(1, 2)
    a.foobar(1, 2, 3)

Вывод:

called  foo
called  bar
called  foobar

Ответ 4

Ну, если вы не хотите явно украшать все свои функции, вы можете получить все функции/методы данного модуля и применить свой декоратор автоматически. не самая простая вещь, но не невозможная в python:)

Вы также можете попробовать аспектно-ориентированную структуру программирования.

my2c