5

我有一个代表接口的抽象基类。此类的子类将此类的其他子类存储为属性。

例如:

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,这会输出一些可读的内容,例如:

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

但是,对于具有子类的AbstractBase类,它会中断,因为很难判断父类从哪里开始,另一个在哪里结束(鉴于上述嵌套没有进一步缩进__repr__)。

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

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

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

4

2 回答 2

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
于 2013-04-22T13:51:35.520 回答
0

这是 John 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  
于 2013-04-22T22:27:55.247 回答