Is it possible to display an objects instance variables in IPython like Matlab does?
ipython, matlab, python
Solution
The short answer is that there is no way to get a list of all attributes of an object in Python, because the attributes could be generated dynamically. For an extreme example, consider this class:
>>> class Spam(object):
... def __getattr__(self, attr):
... if attr.startswith('x'):
... return attr[1:]
>>> spam = Spam()
>>> spam.xeggs
'eggs'
Even if the interpreter could someone figure out a list of all attributes, that list would be infinite.
For simple classes, `spam.__dict__` is often good enough. It doesn't handle dynamic attributes, `__slots__`-based attributes, class attributes, C extension classes, attributes inherited from most of the above, and all kinds of other things. But it's at least something—and sometimes, it's the something you want. To a first approximation, it's exactly the stuff you explicitly assigned in `__init__` or later, and nothing else.
For a best effort aimed at "everything" aimed at human readability, use `dir(spam)`.
For a best effort aimed at "everything" for programmatic use, use `inspect.getmembers(spam)`. (Although in fact the implementation is just a wrapper around `dir` in CPython 2.x, it could do more—and in fact does in CPython 3.2+.)
These will both handle a wide range of things that `__dict__` cannot, and may skip things that are in the `__dict__` but that you don't want to see. But they're still inherently incomplete.
Whatever you use, to get the values as well as the keys is easy. If you're using `__dict__` or `getmembers`, it's trivial; the `__dict__` is, normally, either a `dict`, or something that acts close enough to a `dict` for your purposes, and `getmembers` explicitly returns key-value pairs. If you're using `dir`, you can get a `dict` very easily:
{key: getattr(spam, key) for key in dir(spam)}
One last thing: "object" is a bit of an ambiguous term. It can mean "any instance of a class derived from `object`", "any instance of a class", "any instance of a new-style class", or "any value of any type at all" (modules, classes, functions, etc.). You can use `dir` and `getmembers` on just about anything; the exact details of what that means are described in the docs.
One even-last-er thing: You may notice that `getmembers` returns things like `('__str__', <method-wrapper '__str__' of Spam object at 0x1066be790>`), which you probably aren't interested in. Since the results are just name-value pairs, if you just want to remove `__dunder__` methods, `_private` variables, etc., that's easy. But often, you want to filter on the "kind of member". The `getmembers` function takes a filter parameter, but the docs don't do a great job explaining how to use it (and, on top of that, expect that you understand how descriptors work). Basically, if you want a filter, it's usually `callable`, `lambda x: not callable(x)`, or a `lambda` made up of a combination of `inspect.isfoo` functions.
So, this is common enough you may want to write it up as a function:
def get_public_variables(obj):
return [(name, value) for name, value
in inspect.getmembers(obj, lambda x: not callable(x))
if not name.startswith('_')]
You can turn that into a custom IPython %magic function, or just make a %macro out of it, or just leave it as a regular function and call it explicitly.
In a comment, you asked whether you can just package this up into a `__repr__` function instead of trying to create a %magic function or whatever.
If you've already got all of your classes inheriting from a single root class, this is a great idea. You can write a single `__repr__` that works for all of your classes (or, if it works for 99% of them, you can override that `__repr__` in the other 1%), and then every time you evaluate any of your objects in the interpreter or print them out, you'll get what you want.
However, a few things to keep in mind:
Python has both `__str__` (what you get if you `print` an object) and `__repr__` (what you get if you just evaluate an object at the interactive prompt) for a reason. Usually, the former is a nice human-readable representation, while the latter is something that's either `eval`-able (or typable-into-the-interactive-prompt), or the concise angle-bracket form that gives you just enough to distinguish the type and identity of an object.
That's just a convention rather than a rule, so you can feel free to break it. However, if you are going to break it, you may still want to make use of the `str`/`repr` distinction—e.g., make `repr` give you a complete dump of all the internals, while `str` shows just the useful public values.
More seriously, you have to consider how `repr` values are composed. For example, if you `print` or `repr` a `list`, you get, effectively, `'[' + ', '.join(map(repr, item))) + ']'`. This is going to look pretty odd with a multi-line `repr`. And it'll be even worse if you use any kind of pretty-printer that tries to indent nested collections, like the one that's built into IPython. The result probably won't be unreadable, it'll just defeat the benefits that the pretty-printer is meant to provide.
As for the specific stuff you want to display: That's all pretty easy. Something like this:
def __repr__(self):
lines = []
classes = inspect.getmro(type(self))
lines.append(' '.join(repr(cls) for cls in classes))
lines.append('')
lines.append('Attributes:')
attributes = inspect.getmembers(self, callable)
longest = max(len(name) for name, value in attributes)
fmt = '{:>%s}: {}' % (longest, )
for name, value in attributes:
if not name.startswith('__'):
lines.append(fmt.format(name, value))
lines.append('')
lines.append('Methods:')
methods = inspect.getmembers(self, negate(callable))
for name, value in methods:
if not name.startswith('__'):
lines.append(name)
return '\n'.join(lines)
Right-justifying the attribute names is the hardest part here. (And I probably got it wrong, since this is untested code…) Everything else is either easy, or fun (playing with different filters to `getmembers` to see what they do).
Problem
I'm trying to move away from Matlab to Python. While the magic ? in IPython is nice, one very nice feature of Matlab is that you can see on the command line (by omitting the ;) the instance variables (called properties in Matlab) of the object in question. Is this possible in python (I guess via IPython)? Ideally a class like this: ``` class MyClass(object): _x = 5 @property def x(self): return self._x + 100 @x.setter def x(self, value): self._x = value + 1 def myFunction(self, y): return self.x ** 2 + y ``` Would display something like: ``` mc = Myclass() mc <package.MyClass> <superclass1> <superclass2> Attributes: _x: 5 x: 105 Method Attributes: myFunction(self, y) ``` Is that possible via overriding the print method (if such a thing exits) of the class? Or via a magic method in ipython?