簡體   English   中英

如何獲取從中調用方法的 class?

[英]How to get the class from which a method was called?

get_calling_class function 必須通過返回調用Af方法的方法的 class 來通過以下測試:

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

走堆棧應該給出答案。
理想情況下,答案應該在調用者的堆棧幀中。

問題是,堆棧幀只記錄了 function
名稱(如:'f'、'g'、'h' 等)有關的任何信息
課程丟失。 試圖對丟失的信息進行逆向工程,
通過導航 class 層次結構(與
堆棧框架),並沒有讓我走得太遠,而且變得復雜。

因此,這是一種不同的方法:
將 class 信息注入堆棧幀
(例如使用局部變量),
並從稱為 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

有關的:
從檢查堆棧獲取完全合格的方法名稱


不修改子類的定義:
添加了一個“外部”裝飾器,用於包裝 class 方法。
(至少作為臨時解決方案。)

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

我發現這個鏈接很有趣
(但這里沒有利用元類):
python 中的元類是什么

也許有人甚至可以替換 function 定義*,
其代碼與原始代碼重復的函數;
但添加了當地人/信息,直接在他們的 scope 中。

*
也許在 class 定義完成之后;
可能在 class 創建期間(使用元類)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM