Как заменить str для функции

Я хочу изменить строковое представление функции python, чтобы быть только именем функции.

например, для некоторой функции

def blah(x):
 ...

str(blah) В настоящее время дает

<function blah at 0x10127b578>

поэтому я заменяю __str__ такой:

blah.__str__=lambda: 'blah'

но он не вызывается str(blah).

можно ли изменить __str__ функции?

4 ответов


class NamedFunction:
    def __init__(self, name, f):
        self.f = f
        self.name = name

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

    def __str__(self):
        return self.name


f = NamedFunction("lambda: 'blah'", lambda: 'blah')
print(f())
print(f)

замена __str__ как это не работает на любом типе объекта. Встроенный тип функции не является особенным:

>>> class Foo(object):
    pass

>>> f = Foo()
>>> f.__str__ = lambda: 'f'
>>> str(f)
'<__main__.Foo object at 0x0000000002D13F28>'
>>> f.__str__()
'f'    

на str builtin не ищет __str__ через обычный протокол поиска он переходит прямо к просмотру класса своего аргумента. Таким образом, вы не можете "переопределить"__str__ метод для отдельного объекта; вы должны установить его в классе для применения ко всем объектам этого класса.1

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

class Function(object):
    def __init__(self, raw_function):
        self.raw_function = raw_function
    def __call__(self, *args, **kwargs):
        return self.raw_function(*args, **kwargs)
    def __str__(self):
        return self.raw_function.__name__

на __call__ метод означает, что вы можете вызывать объекты этого класса точно так же, как если бы они были функциями. Этот просто передает все аргументы, которые он получает, прямо в базовую необработанную функцию и возвращает все, что он возвращает (или выбрасывает все исключения, которые он выбрасывает). И поскольку этот класс принимает функцию в качестве аргумента, он также соответствует модели декоратор:

@Function
def blah(x):
    return x + 1

С:

>>> blah
<__main__.Function object at 0x0000000002D13EB8>
>>> str(blah)
'blah'
>>> blah(33)
34

1 встроенный тип функции is специальный в некоторых отношениях (я солгал), один из которых заключается в том, что вы не можете назначить его атрибутам (это атрибуты класс, а не атрибуты какого-либо конкретного объекта функции). Поэтому, прежде чем вы думаете, может быть, было бы здорово, если бы вы могли monkeypatch встроенный тип функции, так что str работала так вы хотите на все функции, это не работает. Вероятно, это к лучшему; изменение таких глобальных и фундаментальных вещей, как тип встроенной функции, было бы отличным способом изобрести некоторые действительно странные ошибки.


class FNMagic:
     def __init__(self,fn,fn_name):
         self.fn = fn 
         self.fn_name = fn_name
     def __call__(self,*args,**kwargs):
         return self.fn(*args,**kwargs)
     def __str__(self):
         return self.fn_name


def blah(x):
    return x

blah = FNMagic(blah,"blah!")
print blah

вы могли бы сделать простой декоратор

class NamedFn:
    def __init__(self,name):
       self.fn_name = name
    def __call__(self,fn):
        return FNMagic(fn,self.fn_name)

@NamedFn("some_name!!!")
def blah2(x,y):
     return x*y

print blah2

Как уже отмечалось, ответа нет. Если вы просто хотите, чтобы получить имя функции в виде строки, вы можете использовать blah.__name__.