253

I have a class Animal with several properties like:


class Animal(object):
    def __init__(self):
        self.legs = 2
        self.name = 'Dog'
        self.color= 'Spotted'
        self.smell= 'Alot'
        self.age  = 10
        self.kids = 0
        #many more...

I now want to print all these properties to a text file. The ugly way I'm doing it now is like:


animal=Animal()
output = 'legs:%d, name:%s, color:%s, smell:%s, age:%d, kids:%d' % (animal.legs, animal.name, animal.color, animal.smell, animal.age, animal.kids,)

Is there a better Pythonic way to do this?

Idr
  • 6,000
  • 6
  • 34
  • 49
  • 1
    Did you try searching for questions related to locating all properties of a class? It's been asked. http://stackoverflow.com/questions/1215408/how-to-list-all-class-properties for example. – S.Lott May 11 '11 at 19:52
  • 8
    @S.Lott: Although the OP asked specifically about properties of a class, from their example code I think it's fairly obvious they're *not* taking about data descriptors. – martineau May 11 '11 at 20:28
  • Relevant: http://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python – sancho.s ReinstateMonicaCellio Apr 24 '16 at 13:43
  • Python offers the vars() function which returns a 'dictionary' of all the instance attributes along with their values. It is similar to the above methods, the only difference being, vars() focuses only on instance attributes and also returns their values along with them. – Syamlal Sep 01 '23 at 07:05

6 Answers6

449

In this simple case you can use vars():

an = Animal()
attrs = vars(an)
# {'kids': 0, 'name': 'Dog', 'color': 'Spotted', 'age': 10, 'legs': 2, 'smell': 'Alot'}
# now dump this in some way or another
print(', '.join("%s: %s" % item for item in attrs.items()))

If you want to store Python objects on the disk you should look at shelve — Python object persistence.

John R Perry
  • 3,916
  • 2
  • 38
  • 62
Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
  • 4
    Oh nice, never used `vars` like that! I thought it just acted like `locals()`, didn't know you could use it on a class/module. Very useful! – Zach Kelling May 11 '11 at 20:03
  • 19
    `vars` only works if you are using `__dict__` to store the attributes (which is the default behaviour for Python objects). Refer to @BasicWolf's answer if you are using `__slots__` – Arnaud Courtecuisse Feb 20 '14 at 10:23
  • Note that in this way you get unordered results. If you need to print for example in order of declaration, and you do not want to do it manually, check [this](http://stackoverflow.com/questions/11296010/iterate-through-class-members-in-order-of-their-declaration) – Matteo A Aug 14 '15 at 08:41
  • How would you use this to print something like: an.name = Dog? I tried the following, does not work. '''f.write('\n'.join(["{}.{} = '{}'".format(myname.name, (k for k in myname.__dict__.keys()),(v for v in myname.__dict__.values()))]))''' – user3710436 Mar 30 '20 at 16:56
  • 4
    ``TypeError: vars() argument must have __dict__ attribute`` – Shaun Han Oct 28 '21 at 10:59
118

Another way is to call the dir() function (see https://docs.python.org/2/library/functions.html#dir).

a = Animal()
dir(a)   
>>>
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__',
 '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', 
 '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
 '__weakref__', 'age', 'color', 'kids', 'legs', 'name', 'smell']

Note, that dir() tries to reach any attribute that is possible to reach.

Then you can access the attributes e.g. by filtering with double underscores:

attributes = [attr for attr in dir(a) 
              if not attr.startswith('__')]

This is just an example of what is possible to do with dir(), please check the other answers for proper way of doing this.

Zaur Nasibov
  • 22,280
  • 12
  • 56
  • 83
  • 8
    This is probably the right approach, but it should be pointed out that what it's doing is printing out the *attributes*, not the things called Properties in new-style classes in Python, and that it's doing it based on an *instance* of a class, not the class itself (because these attributes don't exist until the class instance is created and __init__() is called). Also if any other attributes are created later, they will be omitted, obviously. – martineau May 11 '11 at 20:52
  • Indeed. But I bet, it's really hard to teach one the overwhelming power of Python's dynamic constructions (objects, types, meta-classes, classes) unless one face them. – Zaur Nasibov May 11 '11 at 21:22
  • absolutely, what i was looking for. Thanks. – Amyth Apr 12 '13 at 11:23
  • 1
    A better filtering (by user235925 on http://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python) [attr for attr in dir(a) if not callable(getattr(Animal,attr)) and not attr.startswith("__")] – Yuval Atzmon May 28 '14 at 08:01
  • Works with @property as well – ClementWalter Sep 14 '18 at 06:48
  • The only thing that works with PyUNO LibreOffice API. – Hi-Angel Jul 14 '19 at 23:26
  • `filter(lambda x: not x.startswith('__'), dir(object))` - for list only `filter(lambda x: not x.startswith('__'), object.__dict__)` - for dict. For class attributes you will want to access `object.__class__` and then dir it or `__dict__` – Adam Jan 15 '20 at 23:28
  • 1
    This is an fast and easy way to inspect any object, since an unfamiliar object may seem like a "dark box", you "unveil" its methods and attributes. – RicHincapie Aug 10 '20 at 19:15
75

Maybe you are looking for something like this?

    >>> class MyTest:
        def __init__ (self):
            self.value = 3
    >>> myobj = MyTest()
    >>> myobj.__dict__
    {'value': 3}
Urjit
  • 1,150
  • 8
  • 15
  • 5
    Note since this gives you a dictionary, you can also just look at the keys if you want a quick API reference `print(o.__dict__.keys())`. – awiebe Feb 21 '18 at 07:21
11

try ppretty:

from ppretty import ppretty


class Animal(object):
    def __init__(self):
        self.legs = 2
        self.name = 'Dog'
        self.color= 'Spotted'
        self.smell= 'Alot'
        self.age  = 10
        self.kids = 0


print ppretty(Animal(), seq_length=10)

Output:

__main__.Animal(age = 10, color = 'Spotted', kids = 0, legs = 2, name = 'Dog', smell = 'Alot')
Symon
  • 1,626
  • 1
  • 23
  • 31
6

Here is full code. The result is exactly what you want.

class Animal(object):
    def __init__(self):
        self.legs = 2
        self.name = 'Dog'
        self.color= 'Spotted'
        self.smell= 'Alot'
        self.age  = 10
        self.kids = 0

if __name__ == '__main__':
    animal = Animal()
    temp = vars(animal)
    for item in temp:
        print item , ' : ' , temp[item]
        #print item , ' : ', temp[item] ,
JaeWoo So
  • 568
  • 5
  • 18
4

Just try beeprint

it prints something like this:

instance(Animal):
    legs: 2,
    name: 'Dog',
    color: 'Spotted',
    smell: 'Alot',
    age: 10,
    kids: 0,

I think is exactly what you need.

Anyany Pan
  • 659
  • 7
  • 9