如何获得调用方法的类? [英] How to get the class from which a method was called?
问题描述
get_calling_class
函数必须通过返回称为 Af
方法的方法的类来通过以下测试:
The get_calling_class
function must pass the following tests by returning the class of the method that called the A.f
method:
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
推荐答案
在栈上行走应该给出答案。
理想情况下,答案应该是
Walking the stack should give the answer.
The answer should ideally be, in the caller's stack frame.
问题是,堆栈帧仅记录函数
名称(例如:'f','g','h '等)。有关
类的所有信息都将丢失。试图通过导航类层次结构(与
堆栈框架并行)来对丢失的信息进行逆向工程,这并没有使我走得太远,而且变得很复杂。
The problem is, the stack frames only record the function
names (like so: 'f', 'g', 'h', etc.) Any information about
classes is lost. Trying to reverse-engineer the lost info,
by navigating the class hierarchy (in parallel with the
stack frame), did not get me very far, and got complicated.
因此,这是另一种方法:
将类信息注入堆栈帧中
(例如,带有局部变量),
并从调用的函数中读取。
So, here is a different approach:
Inject the class info into the stack frame
(e.g. with local variables),
and read that, from the called function.
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
相关:
get-fully-qualified-method-name-from-inspect-stack
不修改子类的定义:
添加了外部装饰器,以包装类方法。
(至少作为一个临时解决方案。)
Without modifying the definition of subclasses:
Added an "external" decorator, to wrap class methods.
(At least as a temporary solution.)
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
I found this link very interesting
(but didn't take advantage of metaclasses here):
what-are-metaclasses-in-python
也许有人甚至可以用其代码与原始代码重复的函数替换函数定义*,
;
,但直接在其范围内添加了本地信息/信息。
Maybe someone could even replace the function definitions*,
with functions whose code is a duplicate of the original;
but with added locals/information, directly in their scope.
*
也许在类定义完成后;
可能在类创建期间(使用元类)。
*
Maybe after the class definitions have completed;
maybe during class creation (using a metaclass).
这篇关于如何获得调用方法的类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!