Search code examples
pythonpython-2.7lambdaclass-method

Calling lambda method defined in class scope (as a class attribute)


class _GhostLink(object):
    toGhost = lambda filename: False

class _Mod_AllowGhosting_All(_GhostLink):
    def _loop(self):
        # ...
        if self.__class__.toGhost(fileName) != oldGhost:...

produces:

Traceback (most recent call last):
  File "bash\basher\mod_links.py", line 592, in Execute
    changed = self._loop()
  File "bash\basher\mod_links.py", line 587, in _loop
    if self.__class__.toGhost(fileName) != oldGhost:
TypeError: unbound method <lambda>() must be called with _Mod_AllowGhosting_All instance as first argument (got Path instance instead)

while passing an instance as in if self.toGhost(fileName) != ... results in:

Traceback (most recent call last):
  File "bash\basher\mod_links.py", line 592, in Execute
    changed = self._loop()
  File "bash\basher\mod_links.py", line 587, in _loop
    if self.toGhost(fileName) != oldGhost:
TypeError: <lambda>() takes exactly 1 argument (2 given)

How come toGhost behaves as a classmethod instance method ?

EDIT: I know the difference of class,static etc methods - this is a syntactic question


Solution

  • The reason this happens is fundamentally that lambda and def do the same thing, except that def also assigns a variable, That is, both constructs produce a function.

    The binding of a function (whether from lambda or def) into an instance method happens because functions are also descriptors; remember, in every single case:

    foo = lambda (...): (...)
    

    is identical to:

    def foo(...):
        return (...)
    

    so when you say:

    class _GhostLink(object):
        toGhost = lambda filename: False
    

    It's the same as if you had said:

    class _GhostLink(object):
        def toGhost(filename): 
            return False
    

    So the moral of the story is that you should probably never use lambda as the right side of an assignment; it's not "better" or even different from using def. All it does is confuse.