How to list all fields of a class (and no methods)?
Solution 1
You can get it via the __dict__
attribute, or the built-in vars
function, which is just a shortcut:
>>> class A(object):
... foobar = 42
... def __init__(self):
... self.foo = 'baz'
... self.bar = 3
... def method(self, arg):
... return True
...
>>> a = A()
>>> a.__dict__
{'foo': 'baz', 'bar': 3}
>>> vars(a)
{'foo': 'baz', 'bar': 3}
There's only attributes of the object. Methods and class attributes aren't present.
Solution 2
You could use the built-in method vars()
Solution 3
The basic answer is "you can't do so reliably". See this question.
You can get an approximation with [attr for attr in dir(obj) if attr[:2] + attr[-2:] != '____' and not callable(getattr(obj,attr))]
.
However, you shouldn't rely on this, because:
Because
dir()
is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases.
In other words, there is no canonical way to get a list of "all of an object's attributes" (or "all of an object's methods").
If you're doing some kind of dynamic programming that requires you to iterate over unknwon fields of an object, the only reliable way to do it is to implement your own way of keeping track of those fields. For instance, you could use an attribute naming convention, or a special "fields" object, or, most simply, a dictionary.
Solution 4
This should work for callables:
[f for f in dir(o) if not callable(getattr(o,f))]
You could get rid of the rest with:
[f for f in dir(o) if not callable(getattr(o,f)) and not f.startswith('__')]
Solution 5
You can iterate through an instance's __dict__
attribute and look for non-method things.
For example:
CALLABLES = types.FunctionType, types.MethodType
for key, value in A().__dict__.items():
if not isinstance(value, CALLABLES):
print(key)
Output:
foo
bar
You can do it in a single statement with a list comprehension:
print([key for key, value in A.__dict__.items() if not isinstance(value, CALLABLES)])
Which would print ['foo', 'bar']
.
Eric Wilson
Software developer, experienced in Java and Python in Linux environments, formerly a professor of mathematics. I'm a father of five children, and a husband of one wife.
Updated on November 13, 2020Comments
-
Eric Wilson over 3 years
Suppose
o
is a Python object, and I want all of the fields ofo
, without any methods or__stuff__
. How can this be done?I've tried things like:
[f for f in dir(o) if not callable(f)] [f for f in dir(o) if not inspect.ismethod(f)]
but these return the same as
dir(o)
, presumably becausedir
gives a list of strings. Also, things like__class__
would be returned here, even if I get this to work. -
2rs2ts about 10 yearsThis is per-instance.
-
2rs2ts about 10 yearsAlmost. I got
['__dict__', '__doc__', '__module__', '__weakref__', 'a', 'b']
with a dummy class witha
andb
as class members. -
Eric Wilson about 10 yearsClose, but still includes
__dict__
,__doc__
, etc. -
Admin about 10 yearsThis is probably the best approximation you're going to get, but it should be noted that this considers callable instance attributes (which are sometimes used and are effectively like methods) as non-methods and considers class attributes with no corresponding instance attribute not a field (even though it acts like one for most purposes). It also ignores properties and fails on classes with
__slots__
, which may or may not matter. -
2rs2ts about 10 yearsI'm not sure, but if you can create your own members surrounded by double underscores, this'll break.
-
BrenBarn about 10 years@2rs2ts: Yes, that is true. There is no way around that. There's no way to programatically tell if a double-underscore name is "magic" or not; you have to read the documentation.
-
Benjamin Toueg about 10 yearsThese are naming conventions, you shouldn't create your own members by surrounding them with double underscores.
-
Blckknght about 10 yearsThere's no need to filter out methods, since they're in the class
__dict__
, not the instance__dict__
s. -
martineau about 10 years@Blckknght: I put the test in because a class is an object, too. However, I realized after your comment the need to check for than one type of callable, and have modified my answer. Thanks. If one can assume that the object is a new-style class instance, then what you said is true and the
for
loops could be simplified. -
martineau about 6 years@Benjamin: Indeed. At the end of the Descriptive: Naming Styles section of PEP 8 - Style Guide for Python Code, regarding names with both double-underscore-prefix & suffixes, it says "Never invent such names; only use them as documented."
-
Eray Erdin about 5 yearsI'm in favor of calling other methods instead of mangled magic methods and properties in Python. I think this is much more Pythonic way. So, take my +1.
-
John Sohn over 2 yearsalso doesn't work if __dict __ is not defined. which it isn't always.
-
John Sohn over 2 yearsslots doesn't always contain everything you're looking for either.
-
John Sohn over 2 yearsTraceback (most recent call last): File "<string>", line 1, in <module> TypeError: vars() argument must have dict attribute
-
John Sohn over 2 yearsI'm starting to find myself in agreement with this.
-
John Sohn over 2 yearsI'd add this.[f for f in dir(m) if not callable(getattr(m,f)) and not f.startswith('__')]
-
El Bert over 2 years@JohnSohn hard to figure out the issue from just the error message but it is telling us that whatever is passed to
vars()
doesn't have a__dict__
attribute indicating that what's passed probably isn't anobject
. And indeed witha = "text"; vars(a)
we get a similar message.