2010-02-04 40 views
15

是否可以從框架對象中檢索任何類信息?我知道如何獲取文件(frame.f_code.co_filename),函數(frame.f_code.co_name)和行號(frame.f_lineno),但希望能夠獲取活動對象的類的名稱框架的實例(如果不是實例,則爲None)。Python:如何從'框架'對象檢索類信息?

回答

16

我不相信,在框架對象級別,有任何方法可以找到已調用的實際python函數對象。

但是,如果你的代碼依賴於共同約定:命名方法self的實例參數,那麼你可以做到以下幾點:

def get_class_from_frame(fr): 
    import inspect 
    args, _, _, value_dict = inspect.getargvalues(fr) 
    # we check the first parameter for the frame function is 
    # named 'self' 
    if len(args) and args[0] == 'self': 
    # in that case, 'self' will be referenced in value_dict 
    instance = value_dict.get('self', None) 
    if instance: 
     # return its class 
     return getattr(instance, '__class__', None) 
    # return None otherwise 
    return None 

如果你不想使用getargvalues,你可以直接使用frame.f_locals而不是value_dictframe.f_code.co_varnames[:frame.f_code.co_argcount]而不是args

請記住,這仍然只是依靠慣例,所以它是不可移植的,並且容易出錯:

  • 如果非法功能使用self作爲第一個參數名稱,然後get_class_from_frame將錯誤返回第一個參數的類。
  • 使用描述符時它可能會引起誤解(它將返回描述符的類,而不是被訪問的實際實例)。
  • @classmethod@staticmethod將不會採取self參數,並與描述符一起實現。
  • ,肯定有很多更取決於正是你想做的事

,你可能要花費一些時間來深入挖掘,並找到解決方法的所有這些問題(你可以檢查框功能存在於返回的類和共享相同的來源,檢測描述符調用是可能的,類方法相同等。)

+0

感謝您的回答,Clément;它是詳細和周到的。我仍然希望獲得不止一個迴應!但是,如果沒有,這一個將足以... – 2010-02-08 23:32:17

+0

好吧,等待足夠長。這是一個很好的答案!我曾希望能從框架結構中獲得更好的支持,但事實就是如此。再次感謝克萊門特! – 2010-02-11 23:16:19

+1

要添加一個到列表中,請注意'自己'可能是一個派生類的實例,可能不是我們感興趣的類。 – gertjan 2013-03-29 13:38:08

7

這有點短,但大致相同。如果班級名稱不可用,則返回無。

def get_class_name(): 
    f = sys._getframe(1) 

    try: 
     class_name = f.f_locals['self'].__class__.__name__ 
    except KeyError: 
     class_name = None 

    return class_name 
+0

好的答案!更好的是,你可以做''f.f_locals ['__ class __'] .__ name__'',它也應該覆蓋''classmethod''和''staticmethod''的情況。 – 2015-01-07 21:38:06

+2

@LucioPaiva不起作用。在f_locals中沒有關鍵的'__class __'。 – Pithikos 2015-05-15 16:01:32

2

我剛剛遇到這篇文章,因爲我遇到了同樣的問題。然而,我並沒有將「自我」方法視爲可接受的解決方案,因爲已經列出的所有原因。

下面的代碼演示了一種不同的方法:給定一個框架對象,它在全局變量中搜索匹配成員名稱和代碼塊的對象。搜索並不全面,所以有可能不是所有的類都會被發現,但是找到的類應該是我們正在尋找的類,因爲我們驗證了匹配的代碼。代碼

對象是在前面加上函數名與它的類名,如發現:

def get_name(frame): 
    code = frame.f_code 
    name = code.co_name 
    for objname, obj in frame.f_globals.iteritems(): 
    try: 
     assert obj.__dict__[name].func_code is code 
    except Exception: 
     pass 
    else: # obj is the class that defines our method 
     name = '%s.%s' % (objname, name) 
     break 
    return name 

注意使用的__dict__代替getattr防止派生類的醒目。

還請注意,如果self = frame.f_locals['self']; obj = self.__class__給出匹配項或任何obj in self.__class__.__bases__或更深,則可以避免全局搜索,所以確實存在優化/雜交的空間。

1

如果一個方法是一個類方法,該類將是第一個參數。這將打印出每個調用堆棧幀的第一個arg的類型(如果存在):

def some_method(self): 
     for f in inspect.getouterframes(inspect.currentframe()): 
      args, _,_, local_dict = inspect.getargvalues(f[0]) 
      if args: 
       first_arg = args[0] 
       first_value = local_dict[first_arg] 
       print(type(first_value).__name__)