234

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
  • 5,670
  • 4
  • 33
  • 48
  • 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

6 Answers6

411

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,577
  • 2
  • 35
  • 57
Jochen Ritzel
  • 99,912
  • 29
  • 194
  • 188
  • 3
    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! – zeekay May 11 '11 at 20:03
  • 17
    `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
  • 2
    ``TypeError: vars() argument must have __dict__ attribute`` – Shaun Han Oct 28 '21 at 10:59
105

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
  • 21,620
  • 11
  • 51
  • 80
  • 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. – RicarHincapie Aug 10 '20 at 19:15
71

Maybe you are looking for something like this?

    >>> class MyTest:
        def __init__ (self):
            self.value = 3
    >>> myobj = MyTest()
    >>> myobj.__dict__
    {'value': 3}
Urjit
  • 1,110
  • 8
  • 14
  • 4
    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,428
  • 18
  • 30
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
  • 548
  • 5
  • 14
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
  • 569
  • 5
  • 9