Getting attributes of a class
I want to get the attributes of a class, say:
class MyClass():
a = "12"
b = "34"
def myfunc(self):
return self.a
using MyClass.__dict__
gives me a list of attributes and functions, and even functions like __module__
and __doc__
. While MyClass().__dict__
gives me an empty dict unless I explicitly set an attribute value of that instance.
I just want the attributes, in the example above those would be: a
and b
Solution 1:
Try the inspect module. getmembers
and the various tests should be helpful.
EDIT:
For example,
class MyClass(object):
a = '12'
b = '34'
def myfunc(self):
return self.a
>>> import inspect
>>> inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
[('__class__', type),
('__dict__',
<dictproxy {'__dict__': <attribute '__dict__' of 'MyClass' objects>,
'__doc__': None,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'a': '34',
'b': '12',
'myfunc': <function __main__.myfunc>}>),
('__doc__', None),
('__module__', '__main__'),
('__weakref__', <attribute '__weakref__' of 'MyClass' objects>),
('a', '34'),
('b', '12')]
Now, the special methods and attributes get on my nerves- those can be dealt with in a number of ways, the easiest of which is just to filter based on name.
>>> attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
>>> [a for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))]
[('a', '34'), ('b', '12')]
...and the more complicated of which can include special attribute name checks or even metaclasses ;)
Solution 2:
def props(cls):
return [i for i in cls.__dict__.keys() if i[:1] != '_']
properties = props(MyClass)
Solution 3:
Getting only the instance attributes is easy.
But getting also the class attributes without the functions is a bit more tricky.
Instance attributes only
If you only have to list instance attributes just usefor attribute, value in my_instance
.__dict__
.items()
>>> from __future__ import (absolute_import, division, print_function)
>>> class MyClass(object):
... def __init__(self):
... self.a = 2
... self.b = 3
... def print_instance_attributes(self):
... for attribute, value in self.__dict__.items():
... print(attribute, '=', value)
...
>>> my_instance = MyClass()
>>> my_instance.print_instance_attributes()
a = 2
b = 3
>>> for attribute, value in my_instance.__dict__.items():
... print(attribute, '=', value)
...
a = 2
b = 3
Instance and class attributes
To get also the class attributes without the functions, the trick is to use callable()
.
But static methods are not always callable
!
Therefore, instead of using callable(value)
usecallable
(getattr
(MyClass, attribute))
Example
from __future__ import (absolute_import, division, print_function)
class MyClass(object):
a = "12"
b = "34" # class attributes
def __init__(self, c, d):
self.c = c
self.d = d # instance attributes
@staticmethod
def mystatic(): # static method
return MyClass.b
def myfunc(self): # non-static method
return self.a
def print_instance_attributes(self):
print('[instance attributes]')
for attribute, value in self.__dict__.items():
print(attribute, '=', value)
def print_class_attributes(self):
print('[class attributes]')
for attribute in self.__dict__.keys():
if attribute[:2] != '__':
value = getattr(self, attribute)
if not callable(value):
print(attribute, '=', value)
v = MyClass(4,2)
v.print_class_attributes()
v.print_instance_attributes()
Note: print_class_attributes()
should be @staticmethod
but not in this stupid and simple example.
Result for python2
$ python2 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2
Same result for python3
$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2
Solution 4:
myfunc
is an attribute of MyClass
. That's how it's found when you run:
myinstance = MyClass()
myinstance.myfunc()
It looks for an attribute on myinstance
named myfunc
, doesn't find one, sees that myinstance
is an instance of MyClass
and looks it up there.
So the complete list of attributes for MyClass
is:
>>> dir(MyClass)
['__doc__', '__module__', 'a', 'b', 'myfunc']
(Note that I'm using dir just as a quick and easy way to list the members of the class: it should only be used in an exploratory fashion, not in production code)
If you only want particular attributes, you'll need to filter this list using some criteria, because __doc__
, __module__
, and myfunc
aren't special in any way, they're attributes in exactly the same way that a
and b
are.
I've never used the inspect module referred to by Matt and Borealid, but from a brief link it looks like it has tests to help you do this, but you'll need to write your own predicate function, since it seems what you want is roughly the attributes that don't pass the isroutine
test and don't start and end with two underscores.
Also note: by using class MyClass():
in Python 2.7 you're using the wildly out of date old-style classes. Unless you're doing so deliberately for compatibility with extremely old libraries, you should be instead defining your class as class MyClass(object):
. In Python 3 there are no "old-style" classes, and this behaviour is the default. However, using newstyle classes will get you a lot more automatically defined attributes:
>>> class MyClass(object):
a = "12"
b = "34"
def myfunc(self):
return self.a
>>> dir(MyClass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'myfunc']