Reputation: 129
What's the best way to print the contents of a nested class? For example:
class Library():
def __init__(self):
self.shelves = []
self.shelf = self.Shelf()
class Shelf():
def __init__(self):
self.books = []
x = Library()
I know vars(x) works if the class is not nested. But if it is, I get something like:
{'shelf': <__main__.Shelf instance at 0x7f4bae723560>, 'shelves': []}
as the output. How do I get python to print it out as:
{'shelf': {'books': []}, 'shelves': []}
Upvotes: 4
Views: 4842
Reputation: 59526
You are aiming to have a string version of your objects. Python knows two methods for this: __repr__()
and __str__()
. The first is meant to be a string which, if interpreted as Python source, would re-generate the thing it represents. If you just call vars(x)
you receive a dict
of all fields in the given x
. Most means to output this dict
(and probably also yours) make it call the __repr__()
function of each of its contents. That's why you see that ugly string <__main__.Shelf instance at 0x7f4bae723560>
because that's the __repr__()
of your Shelf
object.
I propose to implement it and thus override the standard implementation. You will have to do that in Shelf
:
class Library():
def __init__(self):
self.shelves = []
self.shelf = self.Shelf()
class Shelf():
def __init__(self):
self.books = []
def __repr__(self):
return repr(vars(self))
x = Library()
And while you're at it, you could do the same in your Library
as well; then typing x
alone (i. e. instead of vars(x)
) would also give the nice output:
class Library():
def __init__(self):
self.shelves = []
self.shelf = self.Shelf()
def __repr__(self):
return repr(vars(self))
class Shelf():
def __init__(self):
self.books = []
def __repr__(self):
return repr(vars(self))
x = Library()
And of course you can refactor that out and put that aspect into a base class:
class Representer(object):
def __repr__(self):
return repr(vars(self))
class Library(Representer):
def __init__(self):
self.shelves = []
self.shelf = self.Shelf()
class Shelf(Representer):
def __init__(self):
self.books = []
x = Library()
Upvotes: 6
Reputation: 49330
First, I would recommend that you not nest classes. There isn't really any reason to do so.
Second, you're seeing exactly what you're supposed to: the value for the shelf
variable is a Shelf
object, and you haven't defined any special appearance (or "reproduction") for it. Since vars
is not recursive, you see the default appearance with a memory location.
If you want to see the contents of a vars()
call on a Shelf
object when printing the Shelf
object, you can define a __repr__
method for Shelf
that calls vars()
on itself:
class Library():
def __init__(self):
self.shelves = []
self.shelf = self.Shelf()
class Shelf():
def __init__(self):
self.books = []
def __repr__(self):
return str(vars(self))
>>> x = Library()
>>> vars(x)
{'shelf': {'books': []}, 'shelves': []}
Upvotes: 2