反射调用对象
我想知道如何在 b.func()
这个函数里查看 A
的实例(也就是 A
的实例中的 self
):
class A():
def go(self):
b=B()
b.func()
class B():
def func(self):
# Introspect to find the calling A instance here
4 个回答
1
通过重构你的代码,使其像下面这样工作:
class A():
def go(self):
b = B(self)
b.func()
class B():
def __init__(self, a):
self.a = a
def func(self):
# Use self.a
或者
class A():
def go(self):
b = B()
b.func(self)
class B():
def func(self, a):
# a
5
你把它作为参数传给 b.func()
。
43
一般来说,我们不希望 func
能够访问调用它的 A
实例,因为这样会破坏封装性。也就是说,在 b.func
里面,你应该能够访问传入的参数和关键字参数,以及实例 b
的状态和属性(通过 self
),还有任何全局变量。
如果你想知道哪个对象在调用,合理的方法有:
- 把调用的对象作为参数传给函数
- 在使用
func
之前,明确地把调用者的引用添加到b
实例上,然后通过self
来访问这个引用。
不过,在说完这些注意事项后,还是值得一提的是,Python 的反射能力很强,有时候可以访问调用模块。在 CPython 的实现中,你可以在不改变现有函数签名的情况下,访问调用的 A
实例:
class A:
def go(self):
b=B()
b.func()
class B:
def func(self):
import inspect
print inspect.currentframe().f_back.f_locals["self"]
if __name__ == "__main__":
a = A()
a.go()
输出:
<__main__.A instance at 0x15bd9e0>
这个技巧在调试时可能会很有用。类似的技术在标准库的 logging
模块中也有使用,可以在这里看到,这样日志记录器就能发现源代码、文件名、行号和函数名,而不需要明确传递这些上下文信息。然而,在正常情况下,如果 B.func
实际上需要使用 A
,直接访问调用栈通常不是一个明智的设计选择,因为传递所需的信息会更清晰、更简单,而不是试图“回溯”到调用者。