How to replace __str__ for a function

后端 未结 4 1160
萌比男神i
萌比男神i 2021-01-02 09:58

I want to change the string representation of a python function to be just the function name.

Eg for some function

def blah(x):
 ...
<
相关标签:
4条回答
  • 2021-01-02 10:27

    Replacing __str__ like that never actually works on any type of object. The builtin function type isn't special:

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

    The str builtin doesn't lookup __str__ via the usual lookup protocol, it skips straight to looking at the class of its argument. So you can't "override" the __str__ method on an individual object; you have to set it on a class to apply to all objects of that class.1

    But then again, the builtin function type isn't special. You can make a class that behaves mostly like a function, and use that instead:

    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__
    

    The __call__ method means you can call objects of this class exactly as if they were functions. This one just passes whatever arguments it receives straight through to the underlying raw function and returns whatever it returns (or throws whatever exceptions it throws). And since this class takes a single function as an argument, it also fits the pattern for a decorator:

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

    With that:

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

    1 The builtin function type is special in some regards (I lied), one of which being that you can't assign to its attributes (that's the attributes of the class itself, not the attributes of any particular function object). So before you think maybe it would be great if you could monkeypatch the builtin function type so that str worked the way you want on all functions, that doesn't work. It's probably for the best; modifying things as global and fundamental as the builtin function type would be a great way to invent some really bizarre bugs.

    0 讨论(0)
  • 2021-01-02 10:38
    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
    

    you could make a simple decorator

    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
    
    0 讨论(0)
  • 2021-01-02 10:38

    As noted already, the answer is no. If you just want to get the name of a function as a string, you can use blah.__name__.

    0 讨论(0)
  • 2021-01-02 10:41

    As Joran said:

    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)
    
    0 讨论(0)
提交回复
热议问题