如何在Python中找到调用函数的类?
我想知道在Python中,调用某个函数的类是什么。比如,我有两个类,ClassA和ClassB。我想知道当classb_instance.call_class_a_method()调用class_a.class_a_method()时,调用者是谁。
class ClassA(object):
def class_a_method(self):
# Some unknown process would occur here to
# define caller.
if caller.__class__ == ClassB:
print 'ClassB is calling.'
else:
print 'ClassB is not calling.'
class ClassB(object):
def __init__(self):
self.class_a_instance = ClassA()
def call_class_a_method(self):
self.class_a_instance.class_a_method()
classa_instance = ClassA()
classa_instance.class_a_method()
classb_instance = ClassB()
classb_instance.call_class_a_method()
我希望输出的结果是:
'ClassB is not calling.'
'ClassB is calling.'
看起来inspect这个模块应该可以做到这一点,但我还没弄明白怎么用。
4 个回答
通常,调用者应该知道并使用正确的参数,而不是在被调用的类里做一些神秘的事情。
你是否需要一个工厂类或函数来记录这个类,或者写一个装饰器来处理这个问题呢?
好吧,如果你想查看调用栈,找出是哪个类(如果有的话)调用了它,这其实很简单:
def class_a_method(self):
stack = inspect.stack()
frame = stack[1][0]
caller = frame.f_locals.get('self', None)
如果你想检查调用者是否是 ClassB 类型,应该使用 isinstance(caller, ClassB)
,而不是直接比较 __class__
。不过,这种做法在 Python 中通常不太好,因为 Python 是一种鸭子类型(也就是说,关注的是对象的行为而不是对象的类型)。
正如其他人所说的,你的应用程序很可能需要重新设计,以避免使用 inspect.stack
。这是 CPython 实现中的一个特性,并不能保证在其他 Python 实现中也存在。此外,这样做其实是错误的做法。
一个函数并不“属于”某个类——一个或多个类可能会(但不一定)引用某个特定的函数对象,比如:
def f(self): return g()
class One(object): bah = f
class Two(object): blup = f
def g(): ...
One.bah
和 Two.blup
都是指向同一个函数对象 f
的引用(当在类或它们的实例上访问时,会变成未绑定或绑定的方法对象,但在调用栈中不会留下痕迹)。所以,当你查看
One().f()
与
Two().f()
在这两种情况下调用的 g()
时,确实很难区分——就像下面的例子一样:
f('blah bloh blup')
完全没有涉及“类”的情况(尽管用作 f
的 self
参数的字符串类型是会有的;-)。
我建议不要依赖反射——尤其是那种复杂的、需要很多经验法则的反射,因为要从中获取任何有用的信息对于生产代码来说是很麻烦的:最好重新设计代码以避免这种需求。
出于纯粹的调试目的,在这种情况下,你可以遍历调用栈,直到找到一个第一个参数名为 self
的调用函数,并检查绑定到这个参数名的值的类型——但正如我提到的,这完全是经验性的,因为没有什么强制要求你的调用者在它们的函数是某个类的方法时,必须把第一个参数命名为 self
。
这种经验性的反射会在我刚才给出的三个代码示例中产生类型对象 One
、Two
和 str
——如你所见,这种方法除了调试之外,确实没什么其他用处;-)。
如果你能更清楚地说明你通过这种反射尝试实现的具体目标,我们当然可以更好地帮助你。