Рекурсивно сбрасывать объект

Я не уверен, есть ли стандартный способ сделать это. Я выполнил следующую функцию для сброса всего содержимого объекта. Он должен рекурсивно выгружать под-объекты, поэтому я проверяю InstanceType, но он не работает:

import types

def dump_obj(obj, level=0):
    for a in dir(obj):
        try:
            if type(obj.__dict__[a]) == types.InstanceType:
                dump_obj(obj.__dict__[a], level + 2)
            else:
                try:
                    print " " * level + "%s -> %s" % (a, obj.__dict__[a])
                except:
                    pass
        except:
            pass

Как проверить, является ли элемент самим объектом?

То, что я действительно хочу, это следующее. Дано:

class B:
  def __init__(self):
    self.txt = 'bye'

class A:
  def __init__(self):
    self.txt = 'hello'
    self.b = B()

a = A()

dump_obj(a)

Мне нужен следующий вывод:

txt -> hello
  txt -> bye

Ответ 1

Всегда лучше использовать isinstance(x, y) вместо type(x) == y.

Поскольку в Python все является объектом, делать это не имеет смысла isinstance(attr, object), потому что (я думаю) он всегда возвращает true.

Лучше всего "черный список" определенных типов. Например, вы проверяете, идет ли он дальше, чем int, float, str, unicode, list, dict, set, ..., в противном случае вы просто печатаете его.

Например:

def dump(obj, level=0):
   for a in dir(obj):
      val = getattr(obj, a)
      if isinstance(val, (int, float, str, unicode, list, dict, set)):
           print level*' ', val
      else:
           dump(val, level=level+1)

UPDATE: isinstance учитывает наследование, поэтому, если вы попытаетесь увидеть, является ли объект экземпляром родительского класса, он вернет True, а может и нет при использовании типа.

Поскольку в этом случае вы будете тестировать примитивные типы, в этом случае это может не иметь никакого значения, но в целом isinstance предпочтительнее.

Посмотрите этот пример:

>>> class A(object): pass
... 
>>> class B(A): pass
... 
>>> a, b = A(), B()
>>> type(a)
<class '__main__.A'>
>>> type(a) == A
True
>>> type(b)
<class '__main__.B'>
>>> type(b) == B
True
>>> type(b) == A
False
>>> 

Вы можете проверить документы

Ответ 2

Это рекурсивно сбросит любой объект и все подобъекты. Другие ответы работали для простых примеров, но для сложных объектов им не хватало некоторых данных.

import jsonpickle # pip install jsonpickle
import json

serialized = jsonpickle.encode(obj)
print(json.dumps(json.loads(serialized), indent=2))

ОБНОВЛЕНИЕ: если вы используете формат YAML, он будет еще ближе к вашему примеру.

import yaml # pip install pyyaml
print(yaml.dump(yaml.load(serialized), indent=2))

Ответ 3

Ваш код работает для меня, за исключением того, что вещи печатаются в неправильном порядке (сначала во-первых, что я бы ожидал с рекурсией).

Итак, я изменил порядок (и использовал isinstance(), а также итерацию по __dict__):

import types

def dump_obj(obj, level=0):
    for key, value in obj.__dict__.items():
        if not isinstance(value, types.InstanceType):
             print " " * level + "%s -> %s" % (key, value)
        else:
            dump_obj(value, level + 2)

class B:
  def __init__ (self):
    self.txt = 'bye'

class A:
  def __init__(self):
    self.txt = 'hello'
    self.b = B()

a = A()

dump_obj(a)

производит

txt -> hello
  txt -> bye