Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is the self argument magically passed to instance methods?

I'm doing the code academy stream and I have a little experience in Ruby. I don't understand why the check_angles(self) function needs the self parameter.

The reason I'm confused is that I don't understand what is passing the self parameter to the function when it is called. it seems like the function call (the last line of the code block) is passing self implicitly, but the function requires self explicitly defined as a parameter.

Why is this?

class Triangle(object):
    def __init__(self, angle1, angle2, angle3):
        self.angle1 = angle1
        self.angle2 = angle2
        self.angle3 = angle3

    number_of_sides = 3

    def check_angles(self):
        sum_angles = self.angle1 + self.angle2 + self.angle3
        if sum_angles == 180:
            return True
        else:
            return False

    tri = Triangle(45,34,78)
    tri.check_angles(EMPTY BUT WHY)
like image 749
Zach Smith Avatar asked Jan 11 '23 19:01

Zach Smith


1 Answers

The way this works in Python is that once you instantiate a class Foo with a method bar(self), the function used to create the method is wrapped in an object of type instancemethod which "binds" it to the instance, so that calling foo_inst.bar() actually calls Foo.bar(foo_inst).

class Foo(object):
    def bar(self):
        print "called bar on %s" % self

foo_inst = Foo()

# these 2 calls are equivalent
foo_inst.bar()
Foo.bar(foo_inst)

or, interactively:

>>> Foo.bar
<unbound method Foo.bar>

>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x10675ecd0>>

so as you can see, while still attached directly to the class, bar is an unbound method and still has the self argument, however, when retrieving the method object from a Foo instance, it has become a bound method whose self parameter is already pre-set to the instance you retrieved the method object from.

This is also the reason why self can really be called anything you want such as arg0 or this or me or putin etc.

In fact, it becomes even more visible that methods are actually functions under the hood in this example:

class Foo(object):
    pass

def bar(arg0):
    print "called bar with %s" % arg0

Foo.bar = bar

Foo().bar()  # prints: called bar with <Foo object at 0x10675b2d0>

See also Python Descriptors @ https://docs.python.org/2/howto/descriptor.html for how this is implemented and how you can implement similar schemes yourself.

like image 186
Erik Kaplun Avatar answered Jan 21 '23 16:01

Erik Kaplun