0
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

Mr_and_Mrs_D
  • 27,070
  • 30
  • 156
  • 325
  • 2
    Do you not want to use `@classmethod` on a `def to_ghost(...):`? – Navith May 08 '15 at 19:54
  • 2
    possible duplicate of [What is the difference between a function, an unbound method and a bound method?](http://stackoverflow.com/questions/11949808/what-is-the-difference-between-a-function-an-unbound-method-and-a-bound-method) – tzaman May 08 '15 at 20:02
  • 2
    A `lambda` is no different than any other method definition inside a class body. Unless you mark it as a `@staticmethod` it will expect a `self` parameter. – tzaman May 08 '15 at 20:08
  • @tzaman: yes for some reason the fact that I assign the method to a class attribute made me think it would itself be a "static" method – Mr_and_Mrs_D May 08 '15 at 20:11
  • lambdas are anonymous functions and assigning them to variables like that is usually bad practice. You loose doc strings and decorators and generally cause others to scratch their heads wondering why you did it. Just use a `def` for named functions. – tdelaney May 08 '15 at 20:11
  • @Mr_and_Mrs_D That's not how it works in Python. When you look up *any* function as an attribute of a class instance, it tries to treat it like an instance method unless you explicitly tell it not to (that's what the `@staticmethod` decorator is for). – tzaman May 08 '15 at 20:12

2 Answers2

4

Looks like you want a static method:

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

or:

class _GhostLink(object):
    @staticmethod
    def toGhost(filename):
        return False
Bi Rico
  • 23,350
  • 3
  • 45
  • 67
  • Yes I guessed so - but it still surprises me - I would expect the lambda to be a static method - how come it is interpreted as a instance method? – Mr_and_Mrs_D May 08 '15 at 20:08
  • @Mr_and_Mrs_D You mean "instancemethod", not "classmethod" -- they're different. And the interpretation depends on how the method is looked up. Read up on the "descriptor protocol". – tzaman May 08 '15 at 20:09
  • @tzaman: that's what I would like to see some clarifications on :) – Mr_and_Mrs_D May 08 '15 at 20:11
2

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.

SingleNegationElimination
  • 137,315
  • 28
  • 247
  • 284