Как изменить представление функции Python?

>>> def hehe():
...     return "spam"
... 
>>> repr(hehe)
'<function hehe at 0x7fe5624e29b0>'

Я хочу иметь:

>>> repr(hehe)
'hehe function created by awesome programmer'

Как мне это сделать? Включение функции __repr__ внутри hehe не работает.

EDIT:

В случае, если вы, ребята, задаетесь вопросом, почему я хочу это сделать:

>>> defaultdict(hehe)
defaultdict(<function hehe at 0x7f0e0e252280>, {})

Мне просто не нравится, как это показано здесь.

Ответ 1

Обычно, когда вы хотите что-то изменить в функции, скажем, подписи функции, поведения функции или атрибутов функции, вы должны рассмотреть возможность использования декоратора. Итак, вот как вы можете реализовать то, что хотите:

class change_repr(object):
    def __init__(self, functor):
        self.functor = functor

        #  lets copy some key attributes from the original function
        self.__name__ = functor.__name__
        self.__doc__ = functor.__doc__

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

    def __repr__(self):
        return '<function %s created by ...>' % self.functor.__name__


@change_repr
def f():
    return 'spam'


print f()  # spam
print repr(f)  # <function hehe created by ...>

Обратите внимание, что вы можете использовать только декоратор на основе класса, так как вам нужно переопределить __repr__ метод, который вы не можете сделать с объектом функции.

Ответ 2

Нет, вы не можете изменить представление объекта функции; если вы хотите добавить документацию, вы должны добавить docstring:

def foo():
    """Frob the bar baz"""

и получите доступ к help(foo) или print foo.__doc__.

Вы можете создать вызываемый объект с пользовательским __repr__, который действует точно так же, как функция:

class MyCallable(object):
    def __call__(self):
        return "spam"
    def __repr__(self):
        return 'hehe function created by awesome programmer'

Демо:

>>> class MyCallable(object):
...     def __call__(self):
...         return "spam"
...     def __repr__(self):
...         return 'hehe function created by awesome programmer'
... 
>>> hehe = MyCallable()
>>> hehe
hehe function created by awesome programmer
>>> hehe()
'spam'

Ответ 3

Непосредственно ответ на ваш вопрос, но, возможно, вам действительно нужна документация?

>>> def hehe():
...  '''hehe function created by awesome programmer'''
...  return 'spam'
...
>>> help(hehe)
Help on function hehe in module __main__:

hehe()
    hehe function created by awesome programmer

Ответ 4

Вот немного более гибкая версия того, что у Александра Жукова answer:

def representation(repr_text):
    class Decorator(object):
        def __init__(self, functor):
            self.functor = functor

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

        def __repr__(self):
            return (repr_text % self.functor.__name__ if '%' in repr_text
                    else repr_text)

    return Decorator

from collections import defaultdict

@representation('<function %s created by awesome programmer>')
def f():
    return list

dd = defaultdict(f)
print repr(dd)

Вывод:

defaultdict(<function f created by awesome programmer>, {})

Так как representation() возвращает декоратор, если вы хотите иметь один и тот же шаблон на нескольких функциях, вы можете сделать что-то вроде этого:

myrepr = representation('<function %s created by awesome programmer>')

@myrepr
def f():
    ...

@myrepr
def g():
    ...

etc