1

I have the following code.

class SomeClass:

    a = lambda self: self.b()

    def __init__(self):
        self.b = lambda self: None

s = SomeClass()
s.a()

It give me "TypeError: () takes exactly 1 argument (0 given)". And I want to understand why.

My explanation:

  • a - class method, so s.a() equlas SomeClass.a(s)

  • b - object's attribute (not a method, just a function), that is why self.b() doesn't equal SomeClass.b(self)

    So in a = lambda self: self.b() argument for b is missing.

    Am I right?

    P.S. Is it closure effect?

    class SomeClass:
    
        a = lambda self: self.b()
    
        def __init__(self):
            self.data = 12
            self.b = lambda: self.data
    
    s = SomeClass()
    print s.a()       #12
    s.data = 24
    print s.a()       #24
    
5
  • a = lambda self: self.b(self) ? -- although that seems atrociously unreadable (and maybe not correct). Why use lambda in a class definition like that? Commented Sep 24, 2016 at 15:24
  • @PeterWood That gives another TypeError, you're giving 2 arguments Commented Sep 24, 2016 at 15:27
  • @PeterWood: You're wrong. The self for a is implicitly bound like normal, because a is a method defined on the class (doesn't matter if you use lambda or def, it's still a method, though def is preferred for other reasons, e.g. the method knows its own name). It doesn't happen for b, because b is a function that just happens to be an attribute of the instance, not a method (methods are defined at class definition level, not in instance initializer, you'd need metaprogramming nonsense to make them actual bound methods in the initializer; don't do it). Commented Sep 24, 2016 at 15:44
  • If you're ever assigning a lambda to a name, don't use a lambda. There is no advantage over a def. Commented Sep 24, 2016 at 16:03
  • @JohnColeman it's just an interesting for understanding example. Nobody wants write code in this way. Commented Sep 25, 2016 at 9:30

1 Answer 1

3

Your problem here is the difference between bound methods and functions

Have a simpler example:

class Someclass(object):
    bound = lambda *args: "bound method got {}".format(args)
    def __init__(self):
        self.unbound = lambda *args: "function got {}".format(args)
>>> c = Someclass()

If we look closely, these two functions are not of the same type:

>>> c.bound
<bound method Someclass.<lambda> of <__main__.Someclass object at 0x...>>
>>> c.unbound
<function Someclass.__init__.<locals>.<lambda> at 0x...>

And as a result, when we call them, they receive different arguments:

>>> c.bound(1, 2, 3)
'bound method got (<__main__.Someclass object at 0x...>, 1, 2, 3)'
>>> c.unbound(1, 2, 3)
'unbound got (1, 2, 3)'

Notice that only the "bound" function got a self argument passed in.

Tested in 3.5 - 2.7 might have slightly different names for things

Sign up to request clarification or add additional context in comments.

6 Comments

On your final note: Actually, 3.5 and 2.7 will agree here. The only point of disagreement is what Someclass.a``/Someclass.bound` (accessed on class, not instance) is; in 2.7, it's an "unbound method", in 3.5, it's a plain function (3.5 just has functions and bound methods, no special in-between thing that is "a method waiting to be bound"; accessing a plain function through an instance that is found on the instance's class makes it bind automatically).
Yep, I realize that this avoids the unbound method problem. Although in py2, the lambda prints as the less informative <function <lambda> at 0x...>
As I undrestand, @Eric 's answer and ShadowRanger 's comment to my question are the same explanations. And I think my ideas were similar to your, but you showed it clearer. Thank you!
@Alex: Your example was less clear because one function was calling the other, so there were way more places to be surprised by argument counts. Plus the fact that self is still available to unbound with a closure anyway
@Eric , one more question about closure. Are you talking about following behavior? 'class SomeClass: a = lambda self: self.b() def __init__(self): self.data = 12 self.b = lambda: self.data s = SomeClass() print s.a() # 12 s.data = 24 print s.a() # 24 '
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.