Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I change a Python bound method object's __str__() attribute?

I would like to change the __str__() attribute of one of my class's methods.

(Note: Not to be confused with "trying to change the method __str__()".)

I have a class, MyClass, which has a method 'some_method'. I can change the way MyClass displays itself by:

class MyClass():
    def __init__(self): pass
    def some_method(self): pass
    def __str__(self): return "I'm an instance of MyClass!"

When I instantiate and print MyClass:

print(my_class)

I get:

I'm an instance of MyClass!

When I

print(my_class.some_method)

I get:

<bound method my_class.some_method of <gumble margle object at mumble-jumble>>

I would like to see instead:

some_method in the instance my_class you Dope!

I've tried overriding the str method of some_method:

def some_method(self):
    def __str__(self):
        return "You dope!"

But no love.

Attempting to brute-force it in IPython proved no better:

my_class.some_method.__str__ = lambda: "You Dope!"

gave

AttributeError: 'method' object attribute '__str__' is read-only

Is there an easy way to do this programmatically (preferrably in Python 3)?

like image 482
JS. Avatar asked Jan 25 '14 00:01

JS.


1 Answers

You'll need to use a custom class instead of a class function:

class CustomFunction(object):
    def __init__(self, name):
        self.name = name

    def __call__(func, self):
        # This is the actual function
        pass

    def __get__(func, instance=None, type_=None):
        class CustomMethod(object):
            def __init__(self, instance, type_):
                self.im_self = instance
                self.im_class = type_
            def __call__(self, *args, **kw):
                return func(self.im_self, *args, **kw)
            def __str__(self):
                return '{} in the instance {} you Dope!'.format(func.name, self.im_self)

        return CustomMethod(instance, type_)

then use this in your class:

class MyClass():
    def __init__(self): pass

    some_method = CustomFunction('some_method')

Demo:

>>> print MyClass().some_method
some_method in the instance <__main__.MyClass instance at 0x106b5ccb0> you Dope!

This works because functions are descriptors; they return methods when their __get__ method is called.

like image 83
Martijn Pieters Avatar answered Sep 28 '22 10:09

Martijn Pieters