Python-имя метода печати при вызове методов класса

Мне нужно выполнять определенные операции каждый раз, когда вызываются методы определенного класса (например, регистрировать имя метода). Как это может быть достигнуто в Python в общем виде?

4 ответов


украсьте вызываемые атрибуты из метакласса:

from functools import wraps

def _log_method(val):
    @wraps(val)
    def wrapper(*a, **ka):
        print(val.__name__, 'is called')
        val(*a, **ka)
    return wrapper

class LogMethodCalls(type):
    def __new__(cls, cls_name, bases, attrs):
        for name, attr in attrs.items():
            if callable(attr):
                attrs[name] = _log_method(attr)
        return type.__new__(cls, cls_name, bases, attrs)

class Foo(metaclass=LogMethodCalls):
    def my_method(self):
        pass

Foo().my_method() # my_method is called

предупреждение: этот код работает только для методов, например, методы, которые были украшены @classmethod или @staticmethod не будет регистрироваться (потому что classmethod и staticmethod объекты не callable-они просто не являются дескрипторами данных).


следующие работы для методов класса и статических методов как хорошо:

from functools import wraps

def _log_method(val):
    @wraps(val)
    def wrapper(*a, **ka):
        print('calling', val.__name__)
        val(*a, **ka)
    return wrapper

class LogMethodCalls(type):
    def __new__(cls, cls_name, bases, attrs):
        for name, attr in attrs.items():
            if callable(attr):
                attrs[name] = _log_method(attr)
            elif isinstance(attr, (classmethod, staticmethod)):
                attrs[name] = type(attr)(_log_method(attr.__func__))
        return type.__new__(cls, cls_name, bases, attrs)

class Foo(metaclass=LogMethodCalls):

    def my_instance_method(self):
        pass

    @classmethod
    def my_class_method(cls):
        pass

    @staticmethod
    def my_static_method():
        pass

Foo().my_instance_method() # calling my_instance_method
Foo.my_class_method() # calling my_class_method
Foo.my_static_method() # calling my_static_method

они __func__ атрибуты, которые мы можем украсить.


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

class Foo(object):
    __metaclass__ = LogMethodCalls

в Python 2.


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

import inspect

def log_call():
    print(inspect.stack()[1][3])

def my_func():
    log_call()
    # do stuff

my_func()

выводит my_func.


вы можете реализовать оформителя:

from functools import wraps

def print_function_name(function):
    @wraps(function)
    def do_it():
        print function.__name__
        function()
    return do_it

использование:

class MyClass(object):
    @print_function_name
    def some_function(self):
        pass

например:

>>> my_object = MyClass()
>>> my_object.some_function()
some_function

использование functools.wraps гарантирует, что функция сохраняет свою документацию и имя, а не становится do_it.


взято из https://stackoverflow.com/a/5103895/5270581:
Следующий метод объект класс вызывается при каждом доступе к атрибуту объекта, включая вызовы методов:

    __get_attribute__

поэтому я предлагаю переопределить его, просто добавив вызов функции ведения журнала внутри.
См.https://stackoverflow.com/a/5103895/5270581 (перейти к последнему ответу) для примера кода.