0

Here is a code extracted and adapted from Learning Python, what is the use of lambda in line 5 return lambda *args: '[Getattr str]', it seems print(X.__str__()) expect 0 arguments, is *args unnecessary here?

class GetAttr:
    def __getattr__(self, attr):
        print('getattr: ' + attr)
        if attr == '__str__':
            return lambda *args: '[Getattr str]'
        else:
            return lambda *args: None

X = GetAttr()
print(X.__call__('why', 'any', 'number', 'of', 'arguments', 'here')) 
print(X.__str__())   # but not here? 
hgajshb
  • 227
  • 2
  • 7

4 Answers4

2

When attr == '__str__', the function needs to return a callable object, because __str__ is expected to be a method. Simply returning a string will give you an error complaining that 'str' objects aren't callable.

However, the *args is not needed because __str__ is never called with any arguments. This suffices:

return lambda: '[Getattr str]'

Note that if you use python2 and inherit from object as is recommended, the example doesn't work. And if you use python3, it doesn't work either. This is the output in those cases:

getattr: __call__
None
<__main__.GetAttr object at 0xb728ff6c>

Why isn't __getattr__ invoked when attr == '__str__'?

It's because the base class object already implements a default __str__ method, and our __getattr__ function is only called for missing attributes. To fix the example as it is we must use the __getattribute__ method instead, but beware of the dangers.

class GetAttr(object):
    def __getattribute__(self, attr):
        print('getattr: ' + attr)
        if attr == '__str__':
            return lambda: '[Getattr str]'
        else:
            return lambda *args: None

A better and more readable solution would be to simply override the __str__ method explicitly.

class GetAttr(object):
    def __getattr__(self, attr):
        print('getattr: ' + attr)
        return lambda *args: None

    def __str__(self):
        return '[Getattr str]'

But though it's better python, much of the point of the example is lost.

Community
  • 1
  • 1
Lauritz V. Thaulow
  • 49,139
  • 12
  • 73
  • 92
0

Its for crushing any args handed to it. No matter how many args you put into __str__() it will always ignore them basically.

On the other hand this is horribly terribly written Python. You might wanna try something else instead

Jakob Bowyer
  • 33,878
  • 8
  • 76
  • 91
0

The lambda makes the function return a function.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
0

Yes it is unnecessary in this case, since X.__str__() will always be called without arguments. It depends what behaviour you want when it is incorrectly called with args:

str1 = lambda *args: "[Getattr str]"
str2 = lambda : "[Getattr str]"

str1(1,2,3) #works, args ignored
str2(1,2,3) #throws runtime error
m2o
  • 6,475
  • 6
  • 27
  • 24