1

Look this code:

class MyClass_1():
    @staticmethod
    def method_1(func):
        return func(1, 2, 3)

class MyClass_2():
    my_func = lambda a,b,c : a*b*c # I need to call this method

    def method_2(self):
        result = MyClass_1.method_1(self.my_func)
        print(result)

My error:

TypeError: () takes 3 positional arguments but 4 were given

I need to call the lambda function my_func in the same way as the code above, but a self is appearing from somewhere I don't know and causing this error.

What am I missing?

João Paulo
  • 6,300
  • 4
  • 51
  • 80
  • Do you understand why `def my_func(a,b,c): return a*b*c` wouldn't work? A lambda is just the same as using `def`, if you define it in a class you need to include the `self`. – Duncan Dec 23 '14 at 20:19
  • Yeah.. that's a good thing to think about... wouldn't work even I make it static? – João Paulo Dec 23 '14 at 20:28
  • 2
    With `@staticmethod` it would work, with `@classmethod` you would need a `cls` first parameter. In all respects (except the function name shown in tracebacks) a lambda is neither more nor less than a one line function returning the same expression. – Duncan Dec 23 '14 at 20:35
  • Thats very interesting. Nice information. Thanks!! – João Paulo Dec 23 '14 at 20:39

4 Answers4

4

Since my_func is a class attribute of MyClass_2, you should not be accessing it through self (an instance of the class). Instead, you should be accessing it through the class directly:

result = MyClass_1.method_1(MyClass_2.my_func)
                            ^^^^^^^^^

Demo:

>>> class MyClass_1():
...     @staticmethod
...     def method_1(func):
...         return func(1, 2, 3)
...
>>> class MyClass_2():
...     my_func = lambda a,b,c : a*b*c # I need to call this method
...     def method_2(self):
...         result = MyClass_1.method_1(MyClass_2.my_func)
...         print(result)
...
>>> MyClass_2().method_2()
6
>>>

For more information, you can check out these sources:

Community
  • 1
  • 1
  • Worked. But how/where `self` enter in this history? – João Paulo Dec 23 '14 at 20:09
  • 1
    When you call `my_func` on `self`, Python will implicitly pass a reference to the class instance as the first argument. But `my_func` is a class attribute, which means it doesn't need/use this reference. So, we call it from the class directly to avoid this. –  Dec 23 '14 at 20:14
3

A lambda is just different syntax for defining a function object. Functions in class bodies are always bound and passed a self argument (as they are descriptors).

Simply give your lambda that argument:

my_func = lambda self, a, b, c: a * b * c

The alternative would be for you to unwrap the method and pass in the plain function object:

result = MyClass_1.method_1(self.my_func.__func__)

or to wrap your lambda in a staticmethod object:

my_func = staticmethod(lambda a, b, c: a * b * c)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
2

You need to give your lambda a self argument. Lambdas are just ordinary functions. There is no difference between this:

class Foo():
    my_func = lambda a,b,c : a*b*c

and this

class Foo():
    def my_func(a, b, c):
        return a*b*c

In both cases, my_func is a method, and self will be passed if you call it on an instance.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
1

lambdas are small anonymous functions and can be written in the parameter list of a method directly. Assigning them to a variable is usually not desirable. A typical use of lambda here would be:

class MyClass_1():
    @staticmethod
    def method_1(func):
        return func(1, 2, 3)

class MyClass_2():

    def method_2(self):
        result = MyClass_1.method_1(lambda a,b,c: a*b*c)
        print(result)

MyClass_2().method_2()    
tdelaney
  • 73,364
  • 6
  • 83
  • 116