2013-04-22 39 views
5

我有一个表示接口的抽象基类。此类的子类存储为此类的其他子类的属性。嵌套类实例的有用默认__repr__

例如:

class AbstractBase(object): 
    pass 

class Child(AbstractBase): 
    def __init__(self, cls1, cls2): 
     assert isinstance(cls1, AbstractBase) 
     assert isinstance(cls2, AbstractBase) # just to show they're instances 

     self.cls1 = cls1 
     self.cls2 = cls2 

层次结构的深度和布局不能预先知道,但不会是递归的。

我可以把__repr__放在AbstractBase上,这样我就可以用一种有用的方式看到每个孩子课堂的特点吗?

我目前的做法是:

from pprint import pformat 

class AbstractBase(object): 
    def __repr__(self): 
     return self.__class__.__name__ + '\n' \ 
       + pformat({k:v for k,v in self.__dict__.iteritems() 
          if not '__' in k}) 

对于基类(没有性能,这是的AbstractBase子类,这样输出的东西可读,例如:与AbstractBase

MyClass 
{'var1': 1, 
'var2': 2} 

但是,对于类子类中断,因为很难确定父类的起始位置和结束位置(因为上面的__repr__没有进一步缩进嵌套层次)。

我会很高兴的东西,如下面,想象cls1cls2有一个int属性var

Child 
{'cls1': { 
      'var': 1, 
     }, 
'cls2': { 
      'var': 0, 
     } 
} 

可悲的是,我不知道如何做到这一点(或者如果它甚至有可能) 。有什么想法吗?

+2

你想要的东西,像'高清__repr __(自我,缩进= 1)',虽然可能也没有办法,所以你必须推出自己的一个将其与'pformat'结合起来,而且会有一些奇怪的角落你无法覆盖的案例 – 2013-04-22 13:25:52

回答

2

我喜欢什么,我得到了做这种方式:

class AbstractBase(object): 
    def __repr__(self, indent=2): 
     result = self.__class__.__name__ + '\n' 
     for k,v in self.__dict__.iteritems(): 
      if k.startswith('__'): 
       continue 
      if isinstance(v, AbstractBase): 
       vStr = v.__repr__(indent + 2) 
      else: 
       vStr = str(v) 
      result += ' '*indent + k + ': ' + vStr 
     result += '\n' 
     return result 
+0

我喜欢这个回应。我稍微修改了它以考虑序列,并打印(我认为是)稍微更易读的输出 - 请参阅我的答案。如果没有其他人有任何辉煌的笔触,我会在几天内接受你:) – sapi 2013-04-22 22:25:46

0

这是一个什么样约翰Zwinck提出了一个稍微修改后的版本。

它考虑如何格式化序列,并略微改变格式。然而,目前这并不完美 - 我认为,特别是它会打破字典,因为可迭代的组件只会打印关键字。

def __repr__(self, indent=2): 
     result = self.__class__.__name__ + '\n' 
     items = self.__dict__.items() 

     for i,(k,v) in enumerate(items): 
      if '__' in k: 
       continue  
      if isinstance(v, AbstractBase): 
       vStr = '\n' + ' '*(indent + 2) + v.__repr__(indent + 4) 
      elif isinstance(v, collections.Iterable): 
       s = str(v) 
       bstart = s[0] 
       bend = s[-1] 

       newIndent = indent + 3 
       vStr = '\n' + ' '*(newIndent - 1) + bstart 
       for j,item in enumerate(v): 
        if isinstance(item, AbstractBase): 
         if j: 
          vStr += ' '*newIndent 
         vStr += item.__repr__(newIndent + 2) 
        else:  
         vStr += repr(item) 
        vStr += ',\n' 
       vStr += ' '*(newIndent - 1) + bend 
      else:    
       vStr = str(v) 
      result += ' '*indent + k + ': ' + vStr 

      if i != len(items) - 1: 
       result += '\n' 

     result = re.sub('\n+', '\n', result) 
     return result