如何获得调用方法的类? [英] How to get the class from which a method was called?

查看:74
本文介绍了如何获得调用方法的类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆