Call a class A method from a class B instance? Do I miss something?

Ian Kelly ian.g.kelly at gmail.com
Thu Aug 17 22:40:38 EDT 2017


On Thu, Aug 17, 2017 at 6:03 PM,  <jfong at ms4.hinet.net> wrote:
> I study some codes of a tutorial about tkinter (https://github.com/daleathan/widget-tour-py3) and can't figure out how it works.
>
> Below is the codes from its two major files:
> ----------------------------
> # file infrastructure.py
> ...
> ...
> class callit:
>     def __init__(self, function, *args ):
>         self.f = function
>
>         self.args = args
>
>
>     def __call__(self, *ignored):
>         self.f(*self.args)
>
> ...
>
> ------------------------
> # file widget.py
> ...
> from infrastructure import *
> ...
> class DemoMainWindow(Frame):
>     ...
>     def _fill_textarea(self):
>         ...
>         # bind events
>         self.text.tag_bind(tag, '<Any-Enter>',
>
>              callit(self.demoenter_callback, tag) )
>         ...
>
>     def demoenter_callback(self, tag):
>         ...
>         self.text.configure(cursor='hand2')
>         ...
>
> ----------------------
> My question is that the object which was left by callit(self.demoenter_callback, tag) is a callit instance, and the method it calls is a DemoMainWindow's method.
> How it is possible?

Methods are just functions with a bit of magic [1] that binds the self
argument to them.

DemoMainWindow.demoenter_callback is an unbound method object
(although in Python 3, it's just an ordinary function). When
self.demoenter_callback is evaluated, the result is not the same
unbound method object. Instead you get a different *bound* method
object, which binds the self argument to the DemoMainWindow instance.
The important point is that this binding happens when
self.demoenter_callback is evaluated, not when the method is called.

This bound method object gets passed to the callit object, which saves
it as self.f. Later, it calls self.f() which calls the method that is
still bound to the same DemoMainWindow instance. Note that evaluating
self.f does not *rebind* the method object. Bound method objects never
get rebound; they are only created from unbound methods.

So when self.f() is called the bound DemoMainWindow instance is used
as the value of the self argument. The fact that it was actually
called from a method of callit doesn't matter.

[1] This magic is called the descriptor protocol, and if you want to
play with it you can use it to create your own method types! This is a
topic usually presented to intermediate-level Python programmers.



More information about the Python-list mailing list