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 (перейти к последнему ответу) для примера кода.