Getting attributes of a class

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.


MyClass.__dict__


__module__


__doc__


MyClass().__dict__



I just want the attributes, in the example above those would be: a and b


a


b





possible duplicate of Inspect python class attributes
– Ciro Santilli 新疆改造中心 六四事件 法轮功
Mar 25 '14 at 14:34




14 Answers
14



Try the inspect module. getmembers and the various tests should be helpful.


getmembers



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 ;)





yup this is great! I used this: attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a))) print [a[0] for a in attributes if '_' not in a[0]]
– Mohamed Khamis
Jan 30 '12 at 10:09


attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))


print [a[0] for a in attributes if '_' not in a[0]]





Be careful- that won't include attributes like_this! It'll also avoid "private" attributes, which you might've done on purpose.
– Matt Luongo
Jan 30 '12 at 16:29


like_this





Hi, I loved that too with a slight clarification : in the expression inspect.getmembers(MyClass, ..., MyClass can be replaced by a class or an object, and if you need the list of the values of your objects, you must replace MyClass by your object variable (or self if you put this expression in a def __repr__() method like me).
– geekobi
Sep 15 '17 at 20:23


inspect.getmembers(MyClass, ...


MyClass


MyClass


self


def __repr__()


def props(cls):
return [i for i in cls.__dict__.keys() if i[:1] != '_']

properties = props(MyClass)





This will include method names
– lenhhoxung
Jul 1 '16 at 9:41





Woudn't be more clear to check: if not i.startswith('_') instead of if i[:1] != '_'?
– Mikaelblomkvistsson
Nov 25 '17 at 15:08


if not i.startswith('_')


if i[:1] != '_'



myfunc is an attribute of MyClass. That's how it's found when you run:


myfunc


MyClass


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.


myinstance


myfunc


myinstance


MyClass



So the complete list of attributes for MyClass is:


MyClass


>>> 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.


__doc__


__module__


myfunc


a


b



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.


isroutine



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():


class MyClass(object):


>>> 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']





One cannot depend on dir(): "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." (see documentation of dir()).
– Tadeck
Jan 30 '12 at 1:31


dir()


dir()





@Tadeck: Good point. I was using it illustratively rather than suggesting it as a solution, since it wouldn't easily allow you to filter the attributes based on what they refer to. But I should be more explicit about that.
– Ben
Jan 30 '12 at 2:02



MyClass().__class__.__dict__


MyClass().__class__.__dict__



However, the "right" was to do this is via the inspect module.





MyClass().__class__.__dict__ == MyClass.__dict__
– yak
Jan 30 '12 at 4:03


MyClass().__class__.__dict__


MyClass.__dict__





@yak's comment isn't quite true. See the following about the differences between class and instance attributes. See stackoverflow.com/questions/35805/….
– sholsapp
Feb 16 '15 at 18:33



I don't know if something similar has been made by now or not, but I made a nice attribute search function using vars(). vars() creates a dictionary of the attributes of a class you pass through it.


class Player():
def __init__(self):
self.name = 'Bob'
self.age = 36
self.gender = 'Male'

s = vars(Player())
#From this point if you want to print all the attributes, just do print(s)

#If the class has a lot of attributes and you want to be able to pick 1 to see
#run this function
def play():
ask = input("What Attribute?>: ")
for key, value in s.items():
if key == ask:
print("self. = ".format(key, value))
break
else:
print("Couldn't find an attribute for self.".format(ask))



I'm developing a pretty massive Text Adventure in Python, my Player class so far has over 100 attributes. I use this to search for specific attributes I need to see.



My solution to get all attributes (not methods) of a class


def get_class_attrs(cls):
return re.findall(r'w+(?=[,)])', cls.__dict__['__doc__'])



I recently needed to figure out something similar to this question, so I wanted to post some background info that might be helpful to others facing the same in future.



Here's how it works in Python (from https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy):



MyClass is a class object, MyClass() is an instance of the class object. An instance's __dict__ only hold attributes and methods specific to that instance (e.g. self.somethings). If an attribute or method is part of a class, it is in the class's __dict__. When you do MyClass().__dict__, an instance of MyClass is created with no attributes or methods besides the class attributes, thus the empty __dict__


MyClass


MyClass()


__dict__


self.somethings


__dict__


MyClass().__dict__


MyClass


__dict__



So if you say print(MyClass().b), Python first checks the new instance's dict MyClass().__dict__['b'] and fails to find b. It then checks the class MyClass.__dict__['b'] and finds b.


print(MyClass().b)


MyClass().__dict__['b']


b


MyClass.__dict__['b']


b



That's why you need the inspect module, to emulate that same search process.


inspect





Scott - A comment posted as an answer must get deleted, otherwise we'd be drowning in them. However, a partial answer or "helpful nudge" towards a solution is still an answer. You'll see how I reworded your post; hopefully I retained your intent. If not, you can further edit it into shape. Cheers!
– Mogsdad
Mar 9 '16 at 18:35


import re

class MyClass:
a = "12"
b = "34"

def myfunc(self):
return self.a

attributes = [a for a, v in MyClass.__dict__.items()
if not re.match('<function.*?>', str(v))
and not (a.startswith('__') and a.endswith('__'))]



For an instance of MyClass, such as


mc = MyClass()



use type(mc) in place of MyClass in the list comprehension. However, if one dynamically adds an attribute to mc, such as mc.c = "42", the attribute won't show up when using type(mc) in this strategy. It only gives the attributes of the original class.


type(mc)


MyClass


mc


mc.c = "42"


type(mc)



To get the complete dictionary for a class instance, you would need to COMBINE the dictionaries of type(mc).__dict__ and mc.__dict__.


type(mc).__dict__


mc.__dict__


mc = MyClass()
mc.c = "42"

# Python 3.5
combined_dict = **type(mc).__dict__, **mc.__dict__

# Or Python < 3.5
def dict_union(d1, d2):
z = d1.copy()
z.update(d2)
return z

combined_dict = dict_union(type(mc).__dict__, mc.__dict__)

attributes = [a for a, v in combined_dict.items()
if not re.match('<function.*?>', str(v))
and not (a.startswith('__') and a.endswith('__'))]





Really neat solution.
– Liliane
Aug 12 '17 at 20:20



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 use
for attribute, value in my_instance.__dict__.items()


for 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().


callable()



But static methods are not always callable!


callable



Therefore, instead of using callable(value) use
callable(getattr(MyClass, attribute))


callable(value)


callable


getattr


MyClass, attribute))


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 MyClass.__dict__.keys():
if attribute[:2] != '__':
value = getattr(MyClass, 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.


print_class_attributes()


@staticmethod


$ python2 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2


$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2



There is a very simple answer, that should be obvious: getattr


class MyClass(object):
a = '12'
b = '34'
def myfunc(self):
return self.a

>>> getattr(MyClass, 'a')
'12'

>>> getattr(MyClass, 'myfunc')
<function MyClass.myfunc at 0x10de45378>



It works dandy both in Python 2.7 and Python 3.x.



If you want a list of these items, you will still need to use inspect.



You can use dir() in a list comprehension to get the attribute names:


dir()


names = [p for p in dir(myobj) if not p.startswith('_')]



Use getattr() to get the attributes themselves:


getattr()


attrs = [getattr(myobj, p) for p in dir(myobj) if not p.startswith('_')]



This can be done without inspect, I guess.



Take the following class:


class Test:
a = 1
b = 2

def __init__(self):
self.c = 42

@staticmethod
def toto():
return "toto"

def test(self):
return "test"



Looking at the members along with their types:


t = Test()
l = [ (x, eval('type(x.%s).__name__' % x)) for x in dir(a) ]



... gives:


[('__doc__', 'NoneType'),
('__init__', 'instancemethod'),
('__module__', 'str'),
('a', 'int'),
('b', 'int'),
('c', 'int'),
('test', 'instancemethod'),
('toto', 'function')]



So to output only the variables, you just have to filter the results by type, and names not starting with '__'. E.g.


filter(lambda x: x[1] not in ['instancemethod', 'function'] and not x[0].startswith('__'), l)

[('a', 'int'), ('b', 'int'), ('c', 'int')] # actual result



That's it.



Note: if you're using Python 3, convert the iterators to lists.



If you want a more robust way to do it, use inspect.



two function:


def get_class_attr(Cls) -> :
import re
return [a for a, v in Cls.__dict__.items()
if not re.match('<function.*?>', str(v))
and not (a.startswith('__') and a.endswith('__'))]

def get_class_attr_val(cls):
attr = get_class_attr(type(cls))
attr_dict =
for a in attr:
attr_dict[a] = getattr(cls, a)
return attr_dict



use:


>>> class MyClass:
a = "12"
b = "34"
def myfunc(self):
return self.a

>>> m = MyClass()
>>> get_class_attr_val(m)
'a': '12', 'b': '34'



I know this was three years ago, but for those who are to come by this question in the future, for me:


class_name.attribute



works just fine.





except when you get an AttributeError.
– rady
May 28 '15 at 21:40





You don't always know what attribute is beforehand.
– Matt Luongo
Aug 31 '15 at 19:38


attribute






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)