0

So say I am extending an object called Frame (found in 'tkinter'), as shown below,

class GraphRegion(Frame):

    def __init__(self, master):
        Frame.__init__(self,master)

Now, I know why 'master' is needed. Why does Frame.__init__ need 'self'? Doesn't 'self' point to GraphRegion? What is this actually telling the object 'Frame'? Is it to create GraphRegion as a type 'Frame'?

2 Answers 2

3

Because Frame.__init__ is an unbound method.

Only looking up methods on instances produces a bound method, there is an instance to bind self to. Because Frame.__init__ is unbound, you need to pass in the first argument, the instance, explicitly.

You cannot otherwise access that method; self.__init__ is GraphRegion.__init__ bound to self. So if you want to reuse the Frame.__init__ version, you have to go and ask for it from Frame directly.

Essentially, when creating a new instance with, say, `GraphRegion(application), Python does this:

  1. Python creates a new empty instance for the GraphRegion class, let's give it a temporary name new.
  2. Python wants to initialise the instance, so it calls new.__init__(application).
  3. The __init__ attribute is looked up. It is not found on the instance itself, so Python looks at the class next.
  4. __init__ is found on the class. When looking up attributes on the class, if the attribute has supports the descriptor protocol, an extra step takes place: binding. __init__ is bound to the instance, producing a bound method.
  5. Python calls the bound method, passing in application.
  6. The bound method calls the actual __init__ function, passing in new (the instance) and application.
  7. Now, inside GraphRegion.__init__ you have both self (the new instance) and master (bound to the same thing application was bound to), but you need to call the Frame.__init__ method too.
  8. Looking up __init__ on Frame happens directly on the class, so the descriptor protocol has no instance to bind to. An unbound method is returned.
  9. Calling the method, Frame.__init__ cannot be handed a bound instance. You need to pass it in explicitly.

When using new-style classes, you can also use super() to access bound methods on super classes. For Tkinter.Frame that only works in Python 3, in Python 2 the whole Tkinter module still uses old-style classes.

For Python 3, that would look like:

class GraphRegion(Frame):
    def __init__(self, master):
        super().__init__(master)

But, as stated, in Python 2 when using Tkinter, your only option is to directly reference the unbound method retrieved directly from the Frame class.

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

Comments

0

Although Martjin's answer is great, I'm going to expand on it, in some, let's say, "lower level" terms.

Basically, whenever you create a new GraphRegion object (myobject = GraphRegion(master)), __init__ is called with the new object as the first parameter (self), and the master argument as the second parameter.

Basically, if you do this:

myobject = GraphRegion(master)

__init__ get's called like this:

__init__(myobject, master)

This is because you often want to assign properties to specific instances of an object, and self lets you do that. For example, if I had a class Movie, where each instance of it had it's own title, I would use self like this:

class Movie(object):
    def __init__(self, title):
        self.title = title

That way, every instance of Movie can have it's own title.

Now, whenever you run Frame.__init__(self, master), that __init__ function often needs to modify the specific instance of the GraphRegion class you're creating (the object you're creating), and self is that instance, so you pass it to the __init__ method.

2 Comments

So say then I was to add a widget to it, like if I added 'self.labelYEQUALS=Label(self)' into the initialization. Let me see if I understand this. The 'self' is being passed to the 'master' variable. Passing in 'self' into that Label is passing in the current instance of GraphRegion, so therefore the master of the instance of GraphRegion is the master of the label I created. Is that right?
Think of it like this: The Frame class has it's own __init__ method, which probably looks something like this: def __init__(self, master, ...). So, when you call Frame.__init__(self, master), you're basically just calling that __init__ method, with the master parameter being the master of your GraphRegion instance.. The master of the Label you created is your instance of GraphRegion, and the master of the GraphRegion is whatever you passed into the __init__ function when you created it.

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.