Andrey Agibalov
Andrey Agibalov

Reputation: 7694

In Python 2.7, how do I override the string representation of a single function?

How do I override the string representation for a single function in Python?

What I have tried:

>>> def f(): pass
... 
>>> f
<function f at 0x7f7459227758>
>>> f.__str__ = lambda self: 'qwerty'
>>> f
<function f at 0x7f7459227758>
>>> f.__repr__ = lambda self: 'asdfgh'
>>> f 
<function f at 0x7f7459227758>
>>> f.__str__(f)
'qwerty'
>>> f.__repr__(f)
'asdfgh'

I know I can get the expected behavior by making a class with __call__ (to make it look like a function) and __str__ (to customize the string representation). Still, I'm curious if I can get something similar with regular functions.

Upvotes: 3

Views: 482

Answers (2)

ThiefMaster
ThiefMaster

Reputation: 318698

As explained by MartijnPieters, you can't do it without going through a class. But you can easily write a decorator which completely hides the added complexity:

from functools import update_wrapper

class _CustomReprFunc(object):
    def __init__(self, fn, repr_):
        self.fn = fn
        self.repr = repr_
        update_wrapper(self, fn)

    def __repr__(self):
        return self.repr

    def __call__(self, *args, **kwargs):
        return self.fn(*args, **kwargs)


def custom_repr(repr_):
    def decorator(fn):
        return _CustomReprFunc(fn, repr_)
    return decorator

Usage:

@custom_repr('foobar')
def foo():
    """foo function"""
    return 'bar'

Upvotes: 3

Martijn Pieters
Martijn Pieters

Reputation: 1124538

You can't. __str__ and __repr__ are special methods and thus are always looked up on the type, not the instance. You'd have to override type(f).__repr__ here, but that then would apply to all functions.

Your only realistic option then is to use a wrapper object with a __call__ method:

def FunctionWrapper(object):
    def __init__(self, callable):
        self._callable = callable
    def __call__(self, *args, **kwargs):
        return self._callable(*args, **kwargs)
    def __repr__(self):
        return '<custom representation for {}>'.format(self._callable.__name__)

Upvotes: 6

Related Questions