What is function binding in python?

Viewed 120

I was trying to understand the kivy library in python. Below is the complete code.

import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button

class MyGrid(GridLayout):
    def __init__(self, **kwargs):
        super(MyGrid, self).__init__(**kwargs)
        self.cols = 1

        self.inside = GridLayout()
        self.inside.cols = 2

        self.inside.name = TextInput(multiline=False)
        self.inside.add_widget(self.inside.name)
        self.inside.add_widget(Label(text="Name: "))

        self.inside.name = TextInput(multiline=False)
        self.inside.add_widget(self.inside.name)
        self.inside.add_widget(Label(text="Email: "))

        self.inside.name = TextInput(multiline=False)
        self.inside.add_widget(self.inside.name)
        self.inside.add_widget(Label(text="Phno: "))

        self.add_widget(self.inside)

        self.submit = Button(text="Submit", font_size=40)
        self.submit.bind(on_press=self.pressed)
        self.add_widget(self.submit)        

    def pressed(self, instance):
        print("pressed")



class MyApp(App):
    def build(self):
        return MyGrid()


if __name__ == "__main__":
    MyApp().run()

Here, while in MyGrid class, under init method, when I try to bind the submit button(self.submit.bind) with the pressed method, the argument with on_press doesn't include parentheses.

self.submit.bind(on_press=self.pressed)

Why does it work? Is it because it's a python convention to not include parentheses while passing it to a method?

And what is the use of the instance argument in the pressed method?

4 Answers

If you pass the function without parentheses, you are passing the function object itself

self.submit.bind(on_press=self.pressed)

This is generally used for callback mechanisms, among other things. If you added parentheses, self.pressed() would be invoked immediately at that very statement, instead of on_press saving that function to call later, in response to a button click.

Parentheses call the method. In the cases where you omit them, you're passing the method itself as a callback to be invoked later. When the method is called, parentheses are involved, but not until then.

Python is an Object Oriented Language in the sense that everything is an object (even methods). In the example above the bind method takes a callable object as a parameter (so another method).

To get the callable object rather than call the method you omit the brackets.

It helps to see what self.pressed actually evaluates to.

The instance self doesn't have an attribute named pressed. Its class, MyGrid, has a function-valued attribute by that name, though.

So self.pressed evaluates to MyGrid.pressed. But, because the function class implements the descriptor protocol, you don't get a reference to that function object. Instead, you get the result of MyGrid.pressed.__get__(self, MyGrid). And that returns a callable object of type method. That object, when called, will take whatever arguments it receives and immediately pass self and those arguments to a call to MyGrid.pressed.

In short, the value of self.pressed looks a lot like a function that might have been defined like

def bound_method(*args, **kwargs):
    return MyGrid.pressed(self, *args, **kwargs)

self.pressed == MyGrid.pressed
             == MyGrid.__dict__['pressed'].__get__(self, MyGrid)

and when self.pressed is eventually called,

self.pressed(ins) == MyGrid.__dict_['pressed'].__get(self, MyGrid)(self, ins)
Related