Welcome, guest | Sign In | My Account | Store | Cart

This recipe demonstrates the runtime addition of a __str__ method to a class instance. This can sometimes be useful for debugging purposes. It also demonstrates the use of the two special attributes of class instances: '__dict__' and '__class__'.

Python, 24 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import string
import new

def __str__(self):
    classStr = ''
    for name, value in self.__class__.__dict__.items( ) + self.__dict__.items( ): 
        classStr += string.ljust( name, 15 ) + '\t' + str( value ) + '\n'
    return classStr

def addStr(anInstance):
    anInstance.__str__ = new.instancemethod(__str__, anInstance, anInstance.__class__)

# Test it

class TestClass:
    classSig = 'My Sig'
    def __init__(self, a = 1, b = 2, c = 3 ):
        self.a = a
        self.b = b
        self.c = c
    
test = TestClass()
addStr( test )
print test

4 comments

Moshe Zadka 20 years, 8 months ago  # | flag

There is a Better Way to Add Methods To Classes. This method creates a cycle in the object for no reason at all. The following function will add any function to an instance in a cycle free way:

def add_method(self, method, name=None): if name is None: name = method.func_name class new(self.__class__): pass setattr(new, name, method) self.__class__ = new

Use as follows:

def pretty_str(self): pass

add_method(C(), pretty_str, '__str__') Moshe Zadka

Vikas Dhiman 11 years, 3 months ago  # | flag

@Moshe: Doesn't your recipe assumes that no attributes have been set on the object earlier ? Anyway, your recipe suits my purpose. Thanks.

def add_method(self, method, name=None):
    if name is None:
        name = method.func_name
    setattr(self.__class__, name, method)

class C:
    pass

def pretty_str: return "i can be stringified"

o = C()
o.some_attr = 1
add_method(o, pretty_str, "__str__")
print dir(o)  # some_attr is lost
Vikas Dhiman 11 years, 3 months ago  # | flag

Caveat in above code: Directly setting the method on the class will affect other instances of class.

o = C()
add_method(o, pretty_str, "__str__")
print dir(C) # Also has __str__ set to pretty_str
o2 = C()
print dir(o2) # Every new object has __str__ set to pretty_str
Bob Marley 10 years, 8 months ago  # | flag

Time to make this recipe PEP8 compliant, wouldn't you say?

import string
import new

def __str__(self):
    class_str = ''
    for name, value in self.__class__.__dict__.items() + self.__dict__.items(): 
        class_str += string.ljust(name, 15) + '\t' + str(value) + '\n'
    return class_str

def add_str(an_instance):
    an_instance.__str__ = new.instancemethod(__str__, an_instance, an_instance.__class__)

# Test it

class TestClass:
    class_sig = 'My Sig'
    def __init__(self, a=1, b=2, c=3):
        self.a = a
        self.b = b
        self.c = c

test = TestClass()
add_str(test)
print test

Changelog: Changed camelCase and spacing to PEP8 compliant naming conventions.