我们都知道,python有一定的反射能力,比如动态获得函数名:
def my_caller():
my_callee()
def my_callee():
import inspect
frame = inspect.stack()[1].frame
print('the caller is \'{}\'.'.format(frame.f_code.co_name))
my_caller()
以上代码可以打印出:
the caller is 'my_caller'.
但是当caller是一个类时:
class Caller(object):
def run1(self):
my_callee()
@classmethod
def run2(clazz):
my_callee()
@staticmethod
def run3():
my_callee()
caller = Caller()
caller.run1()
caller.run2()
Caller.run3()
以上代码可以打印出方法名,却打印不出类名:
the caller is 'run1'.
the caller is 'run2'.
the caller is 'run3'.
那么,有没有办法,动态地获得调用栈中类的类名呢?
我自己倒是找到了一个不很干净的方法,而且对于staticmethod就无能为力了:
以上代码将输出:
可以看到,这种方法是无法区分普通函数与staticmethod的。
自己事后又分析了一下,感觉python其实并不是纯粹的面向对象语言,到了执行层面,都转化成函数调用了,也就是code对象,而解释器有没有把这个code与其对应的函数对象关联起来(其实是有关联的,只不过是单向的,每个function和method都有一个__code__属性,就是code对象),所以导致无法从code反向逆推出是来自哪个function或method。
所以如果要想反向定位,也就只能自己来维护 code -> function/method 的关系了。其实实现起来也简单,只要把所有的类都扫描一遍就可以了(性能会有点低,真有需要可以把映射关系缓存下来,不用每次都全类扫描),例如: