class MyFrame(Frame): def __init__(self, parent, n): Frame.__init__(self, parent) self.n = nWhy?
Inheritance and overriding
Some people start on Tkinter before getting far enough into learning Python. You should definitely read the Classes chapter in the Python tutorial, but I'll summarize the basics.First, you're subclassing (inheriting from) the Tkinter class Frame. This means instances of your class are also instances of Frame, and can be used like Frames, and can use the internal behavior of Frame.
When someone constructs a MyFrame object by typing MyFrame(root, 3), that creates a new MyFrame instance and calls new_instance.__init__(root, 3).
You've overridden the parent's __init__ method with your own, so that's what gets called.
But if you want to act like a Frame, you need to make sure all the stuff that gets done in constructing a Frame object also gets done in constructing your object. In particular, whatever Tkinter does under the covers to create a new widget in the window manager, connect it up to its parent, etc. all has to get done. So, you need Frame.__init__ to get called for your object to work.
Unlike some other languages, Python doesn't automatically call base class constructors for you; you have to do it explicitly. The advantage of this is that you get to choose which arguments to pass to the parent--which is handy in cases (like this example) where you want to take extra arguments.
Not so super
The normal way to do this is to use the super function, like this:class MyFrame(Frame): def __init__(self, parent, n): super(MyFrame, self).__init__(parent) self.n = nUnfortunately, that doesn't work with Tkinter, because Tkinter uses classic classes instead of new-style classes. So, you have to do this clunky thing instead where you call the method on the class instead of calling it like a normal method.
You don't really want to learn all about classic classes, because they're an obsolete technology. (In Python 3, they no longer exist.) You just need to know two things:
- Never use classic classes when you can help it. If you don't have anything to put as your base class, use object.
- When you can't help it and are forced to use classic classes (as with Tkinter), you can't use super, so you have to call methods directly on the class.
Unbound methods
If you want all the gory details, see How Methods Work. But I'll give a short version here.Normally, in Python—like most other object-oriented languages—you call methods on objects. The way this works is a bit surprising: foo.bar(spam) actually constructs a "bound method" object foo.bar, then calls it like a function, with foo and spam as the arguments. That foo then becomes the self parameter that you have to put in every method definition.
Since classes themselves are just another kind of objects, you can call methods on them too, like FooType.bar(spam). But here, Python doesn't have any bound object to get passed as your self parameter—it constructs an "unbound method" FooType.bar, then calls it with just spam as an argument, so there's nothing to match up with your self parameter. (Python could have been designed to pass the FooType class itself as the self parameter, but that would be confusing more often than it would be useful. When you want that behavior—for example, to create "alternate constructors" like datetime.datetime.now, you have to ask for it explicitly, with the @classmethod decorator.) So, you have to pass it yourself.
In other words, in this code, the two method calls at the end are identical:
class FooType(object): def bar(self, spam): print self, spam foo = FooType() foo.bar(2) FooType.bar(foo, 2)So, why would you ever use the clumsy and verbose second form? Basically, only when you have to. Maybe you want to pass the unbound method around to call on an object that will be created later. Maybe you had to look up the method dynamically. Or maybe you've got a classic class, and you're trying to call a method on your base class.
View comments