关于python:python-每当调用类的方法时print方法名

Python - Print method name whenever the methods of a class is called

每次调用特定类的方法时,我都需要执行某些操作(例如,记录方法名)。如何以通用的方式在Python中实现这一点?


从元类内修饰可调用属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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修饰的方法,这些方法将不会被记录(因为classmethodstaticmethod对象不可调用-它们只是非数据描述符)。

对于类方法和静态方法,也可以使用以下方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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__属性。

请注意,您需要使用

1
2
class Foo(object):
    __metaclass__ = LogMethodCalls

在Python 2中。


摘自这个答案。您可以使用inspect模块查看函数名的堆栈,以创建一个简单的日志记录函数。看起来有点像黑客,但我想它能回答这个问题。

1
2
3
4
5
6
7
8
9
10
import inspect

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

def my_func():
    log_call()
    # do stuff

my_func()

这将打印my_func


您可以实现一个修饰器:

1
2
3
4
5
6
7
8
from functools import wraps

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

用途:

1
2
3
4
class MyClass(object):
    @print_function_name
    def some_function(self):
        pass

例如:

1
2
3
>>> my_object = MyClass()
>>> my_object.some_function()
some_function

使用functools.wraps确保函数保留其文档和名称,而不是成为do_it


摘自https://stackoverflow.com/a/5103895/5270581:对象类的以下方法在每次访问对象的属性时调用,包括方法调用:

1
    __get_attribute__

所以我建议通过向内部的日志函数添加一个调用来覆盖它。代码示例请参见https://stackoverflow.com/a/5103895/5270581(转到最后一个答案)。