如何替换函数的__str__

10 投票
4 回答
4309 浏览
提问于 2025-04-18 00:55

我想把一个Python函数的字符串表示改成只有函数名。

比如说,有一个函数:

def blah(x):
 ...

str(blah) 现在返回的是:

<function blah at 0x10127b578>

所以我像这样替换了 __str__

blah.__str__=lambda: 'blah'

但是用 str(blah) 时并没有调用这个替换。

有没有办法改变函数的 __str__

4 个回答

3

如前所述,答案是否定的。如果你只是想把一个函数的名字变成字符串,可以用 blah.__name__

4
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

你可以创建一个简单的装饰器。

10

像这样替换 __str__ 方法其实在任何类型的对象上都不管用。内置的类型函数并没有什么特别之处:

>>> class Foo(object):
    pass

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

内置的 str 函数并不是通过常规的查找方式来寻找 __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 内置的函数类型在某些方面确实是特别的(我说错了),其中之一就是你不能给它的属性赋值(这里指的是类本身的属性,而不是任何特定函数对象的属性)。所以在你想着如果能修改内置函数类型,让 str所有 函数上都按你想要的方式工作,那是不可能的。这可能是件好事;修改像内置函数类型这样全球性的基本东西,很可能会引入一些奇怪的错误。

6

正如Joran所说:

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)

撰写回答