python - 如何获取调用方法的类?
问题描述
该get_calling_class
函数必须通过返回调用该A.f
方法的方法的类来通过以下测试:
class A:
def f(self): return get_calling_class()
class B(A):
def g(self): return self.f()
class C(B):
def h(self): return self.f()
c = C()
assert c.g() == B
assert c.h() == C
解决方案
走堆栈应该给出答案。
理想情况下,答案应该在调用者的堆栈帧中。
问题是,堆栈帧只记录函数
名称(如:'f'、'g'、'h' 等)。有关
类的任何信息都丢失了。试图
通过导航类层次结构(与
堆栈框架并行)对丢失的信息进行逆向工程,并没有让我走得太远,而且变得复杂。
因此,这是一种不同的方法:
将类信息注入堆栈帧
(例如,使用局部变量),
然后从被调用的函数中读取它。
import inspect
class A:
def f(self):
frame = inspect.currentframe()
callerFrame = frame.f_back
callerLocals = callerFrame.f_locals
return callerLocals['cls']
class B(A):
def g(self):
cls = B
return self.f()
def f(self):
cls = B
return super().f()
class C(B):
def h(self):
cls = C
return super(B, self).f()
def f(self):
cls = C
return super().f()
c = C()
assert c.h() == C
assert c.g() == B
assert c.f() == B
相关:
从检查堆栈获取完全合格的方法名称
不修改子类的定义:
添加了一个“外部”装饰器,用于包装类方法。
(至少作为临时解决方案。)
import inspect
class Injector:
def __init__(self, nameStr, valueStr):
self.nameStr = nameStr
self.valueStr = valueStr
# Should inject directly in f's local scope / stack frame.
# As is, it just adds another stack frame on top of f.
def injectInLocals(self, f):
def decorate(*args, **kwargs):
exec(f'{self.nameStr} = {self.valueStr}')
return f(*args, **kwargs)
return decorate
class A:
def f(self):
frame = inspect.currentframe()
callerDecoratorFrame = frame.f_back.f_back # Note:twice
callerDecoratorLocals = callerDecoratorFrame.f_locals
return callerDecoratorLocals['cls']
class B(A):
def g(self): return self.f()
def f(self): return super().f()
class C(B):
def h(self): return super(B, self).f()
def f(self): return super().f()
bInjector = Injector('cls', B.__name__)
B.g = bInjector.injectInLocals(B.g)
B.f = bInjector.injectInLocals(B.f)
cInjector = Injector('cls', C.__name__)
C.h = cInjector.injectInLocals(C.h)
C.f = cInjector.injectInLocals(C.f)
c = C()
assert c.h() == C
assert c.g() == B
assert c.f() == B
我发现这个链接非常有趣
(但这里没有利用元类):
what-are-metaclasses-in-python
也许有人甚至可以用
代码与原始代码重复的函数替换函数定义*;
但是直接在他们的范围内增加了当地人/信息。
*
可能在类定义完成之后;
可能在类创建期间(使用元类)。
推荐阅读
- node.js - 将 Rust 与 Neon 绑定一起使用时,如何获得回溯或以其他方式调试“无法启动恐慌”?
- kdb - kdb Web 应用程序中的“html/main.html:未找到”错误
- delphi - TSaveDialog 和 2 种具有相同扩展名的格式
- syslog-ng - syslog-ng 错误的原因是什么:“找不到目标插件 http”?
- c++ - 您可以在具有相同表示的类型之间重新解释转换吗?
- docker - 使用修改后的 fabric-server-config 初始化结构 ca
- c# - 在大文件中搜索性能差异
- python - 获取神经网络的预测列表
- kotlin - 听众对第二次呼叫没有反应
- python - 实现骰子游戏