Можно изменить функцию rep в python?

Я видел примеры для установки метода __repr__ в определениях классов. Можно ли изменить функции __repr__ для функций либо в их определениях, либо после их определения?

Я попытался без успеха...

>>> def f():
    pass
>>> f
<function f at 0x1026730c8>
>>> f.__repr__ = lambda: '<New repr>'
>>> f
<function __main__.f>

Ответы

Ответ 1

Да, если вы хотите отказаться от функции, фактически являющейся функцией.

Сначала определите класс для нового типа:

import functools
class reprwrapper(object):
    def __init__(self, repr, func):
        self._repr = repr
        self._func = func
        functools.update_wrapper(self, func)
    def __call__(self, *args, **kw):
        return self._func(*args, **kw)
    def __repr__(self):
        return self._repr(self._func)

Добавить в функцию декоратора:

def withrepr(reprfun):
    def _wrap(func):
        return reprwrapper(reprfun, func)
    return _wrap

И теперь мы можем определить репер вместе с функцией:

@withrepr(lambda x: "<Func: %s>" % x.__name__)
def mul42(y):
    return y*42

Теперь repr(mul42) создает '<Func: mul42>'

Ответ 2

Нет, потому что repr(f) выполняется как type(f).__repr__(f).

Ответ 3

Для этого вам нужно будет изменить функцию __repr__ для данного класса, которая в этом случае является встроенным классом функций (types.FunctionType). Поскольку в Python вы не можете редактировать встроенные классы, только подклассировать их, вы не можете.

Однако есть два подхода, которым вы могли бы следовать:

  • Оберните некоторые функции, предложенные Кватфордом
  • Создайте свой собственный протокол представления со своей собственной функцией репликации. Например, вы можете определить функцию myrepr, которая сначала ищет методы __myrepr__, которую вы не можете добавить в класс функций, но вы можете добавить ее к отдельным объектам функции, как вы предлагаете (а также к вашим пользовательским классам и объектам), тогда по умолчанию будет указано, если __myrepr__ не найден. Возможная реализация для этого:

    def myrepr(x):
      try:
        x.__myrepr__
      except AttributeError:
        return repr(x)
      else:
        return x.__myrepr__()
    

    Затем вы можете определить методы __myrepr__ и использовать функцию myrepr. В качестве альтернативы вы также можете сделать __builtins__.repr = myrepr, чтобы сделать вашу функцию по умолчанию repr и продолжать использовать repr. Этот подход в конечном итоге сделает именно то, что вы хотите, хотя редактирование __builtins__ может не всегда быть желательным.