Лучший способ регистрировать вызовы методов в Python? - PullRequest
17 голосов
/ 24 февраля 2011

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

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 перед каждым определением мета? Есть ли какой-нибудь способ поместить один декоратор выше определения класса, чтобы все вызовы его методов были оформлены / записаны? Или есть другие, более интересные и интересные способы сделать это вместо декоратора?

Ответы [ 4 ]

15 голосов
/ 24 февраля 2011

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

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)
10 голосов
/ 24 февраля 2011

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

#!/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
8 голосов
/ 24 февраля 2011

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

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

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

0 голосов
/ 24 февраля 2011

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

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

my2c

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