Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lambda calling @classmethod fails

Tags:

python

Maybe I get this completely wrong but I ran into some odd issues with lambda calling @classmethod.

I have the following class:

class MyClass:
  LAMBDA = lambda: MyClass.ClassMethod()

  @classmethod
  def ClassMethod(cls):
    pass

But this fails whenever LAMBDA is called with:

TypeError: unbound method <lambda>() must be called with MyClass instance as first argument (got nothing instead)

I don't really understand why this is so. I have already spent some time trying to get that working. I need some class attributes being populated by that lambda and self-referencing the class is obviously not possible at that stage.

like image 710
ja.ro Avatar asked Jul 07 '10 17:07

ja.ro


2 Answers

LAMBDA here is just a normal method. When you look it up on the class, you get an unbound method, which is a sort of silly thing that takes your function and imposes that--though self is not passed yet--the first argument to it must be an instance of the class in question.

To reiterate, LAMBDA = lambda: MyClass.ClassMethod() is not any different than def LAMBDA(): return MyClass.ClassMethod(). In the latter case, it's more clear that you have a sort of broken method definition. A lambda function and a def function form the exact same kinds of object, and Python turns them into methods with the same rules on-the-fly at lookup time.

I suspect the code you might want is

class MyClass(object):
    @classmethod
    def ClassMethod(cls):
        pass
MyClass.LAMBDA = MyClass.ClassMethod

or

class MyClass(object):
    @classmethod
    def ClassMethod(cls):
        pass

    @classmethod
    def LAMBDA(cls):
        return cls.ClassMethod()

(Note this last one could be written with a lambda as you originally did, but there's no reason to. I would never use = lambda in any of my code, personally. Also note that ClassMethod and LAMBDA don't follow normal Python capitalization style rules.)

like image 132
Mike Graham Avatar answered Oct 23 '22 02:10

Mike Graham


You must understand, that your code is exactly equivalent to

class MyClass:

  def LAMBDA():
    return MyClass.ClassMethod()

  @classmethod
  def ClassMethod(cls):
    pass

You, then, apparently call it like MyClass.LAMBDA(). But look, LAMBDA is an instance method. And you are calling it without an actual instance in place.

What exactly are you trying to do?

I reckon, if you are giving a name to a lambda construct, you might as well declare it the 'normal' way - def. From my experience, there are only a few isolated cases when using lambas actually contributes to the code quality.

like image 31
shylent Avatar answered Oct 23 '22 02:10

shylent