The other day, I was trying to figure out if there was an easy way to grab a class’s defined attributes (AKA “instance variables”). The reason was that we were using the attributes we created to match up with the fields in a file we parse. So basically we read a file line-by-line and each line can be split into 150+ pieces that need to be mapped to the fields we create in the class. The catch is that we recently added more fields to the class and there’s a check in the code that is hard-coded with the number of fields that should be in the file. Thus, when I added more fields, it broke the check. I hope that all made sense. Now you know the background, so we can move on. I found three different ways to accomplish this, so we’ll go from the most complex to the simplest.
As most Python programmers should know, Python provides a handy little builtin called dir. I can use that on a class instance to get a list of all the attributes and methods of that class along with some inherited magic methods, such as ‘__delattr__’, ‘__dict__’, ‘__doc__’, ‘__format__’, etc. You can try this yourself by doing the following:
x = dir(myClassInstance)
However, I don’t want the magic methods and I don’t want the methods either. I just want the attributes. To make everything crystal clear, let’s write some code!
######################################################################## class Test: """""" #---------------------------------------------------------------------- def __init__(self): self.varOne = "" self.varTwo = "" self.varThree = "" #---------------------------------------------------------------------- def methodOne(self): """""" print "You just called methodOne!" #---------------------------------------------------------------------- if __name__ == "__main__": t = Test()
What we want to get is a list that only contains self.varOne, self.varTwo and self.varThree. The first method that we will look at is using Python’s inspect module.
import inspect variables = [i for i in dir(t) if not inspect.ismethod(i)]
Doesn’t look too complicated, does it? But it requires an import and I’d prefer not to do that. On the other hand, if you need to do introspection, the inspect module is a great way to go. It’s quite powerful and can tell you lots of wonderful things about your class or one you didn’t even write. Anyway, the next easiest way that I found was to use Python’s callable builtin:
variables = [i for i in dir(t) if not callable(i)]
You can read more about callable in the Python docs. Basically all that callable does is return a True or False depending on whether or not the object you passed it is callable. Methods are callable, variables are not. Thus we loop over each item in the class dict and only append them to the list if they are not callable (i.e. not methods). Pretty slick and it doesn’t require any imports! But there’s an even easier way!
The simplest way that I found was using the magic method, __dict__. This is built into every class you make unless you override it. Since we’re dealing with a Python dictionary, we can just call its keys method!
variables = t.__dict__.keys()
The real question now is, should you use a magic method to do this? Most Python programmer will probably frown on it. They’re magic, so they shouldn’t be used unless you’re doing metaprogramming. Personally, I think it’s perfectly acceptable for this use case. Let me know of any other methods that I’ve missed or that you think are better.
Resources
- StackOverflow: List attributes of an object
- StackOverflow: Python : Assert that variable is instance method?
I’m not sure if you meant to use “dir” in your first 2 examples instead of __dict__, but as you can see from your 3rd example, t.__dict__ ONLY contains the variables anyway. The “inspect.ismethod”, and “callable” aren’t doing anything at all. …and if you meant to use “dir” instead of “dict”, then your first two examples won’t give you what you want anyway.
Yeah, my bad. I had a bunch of examples and I thought I was copying the right ones, but I ended up copying some of the wrong experiments. I corrected the article. Sorry about that.
You can just use the vars builtin function which looks up __dict__ for you:
vars(t).keys()
Neither vars nor __dict__ works when you have __slots__ defined though.
It’s worth making clear that the differences between dir(x) and x.__dict__ are not only methods (nor need they begin ‘_’). Any attribute inherited from parent classes is included in dir() as are any __slots__ (even when they have no value set).
More explicitly, x.__dict__ will give you precisely the attributes that have been set directly on instance x, excluding any named in __slots__.
So you may want to go back and throw together a post contrasting __slots__, __dict__, dir and vars.
Pingback: How to Get a List of Class Attributes in Python « The Black Velvet Room
Pingback: Top 10 Most Read Mouse vs Python Articles of 2019 - The Mouse Vs. The Python