Reputation: 716
So I have a class, Application, with 2 subclasses MyButton and MyLabel. Application also has
self.backgroundcolor = 'orange'
self.textcolor = 'black'
I want to use these two variables in my subclasses MyButton and MyLabel. So, I tried
class MyButton(Button):
def __init__(self, *args, **kwargs):
Button.__init__(self, *args, **kwargs)
self['bg'] = super(Application, self).backgroundcolor
self['fg'] = super(Application, self).textcolor
self['relief'] = FLAT
class MyLabel(Label):
def __init__(self, *args, **kwargs):
Label.__init__(self, *args, **kwargs)
self['fg'] = super(Application, self).textcolor
but it doesn't work, saying that
TypeError: super(type, obj): obj must be an instance or subtype of type
But my Application class looks like
class Application(Frame):
global yearcal
def __init__(self, master=None):
Frame.__init__(self, master)
self.month = 5
self.year = 2014
self.color_clicked = 'lightskyblue'
now = datetime.datetime.now()
self.thisyear = now.year
self.thismonth = now.month
self.today = now.day
self.textcolor = 'purple'
self.bgcolor = 'gray'
self.today_color = 'palegreen1'
self.apt_color = 'light coral'
MORE STUFF HERE...
class MyButton(Button):
def __init__(self, *args, **kwargs):
Button.__init__(self, *args, **kwargs)
self['bg'] = super(Application, self).backgroundcolor
self['fg'] = super(Application, self).textcolor
self['relief'] = FLAT
class MyLabel(Label):
def __init__(self, *args, **kwargs):
Label.__init__(self, *args, **kwargs)
self['fg'] = super(Application, self).textcolor
Upvotes: 0
Views: 795
Reputation: 321
There is a confusion in this example between a nested class, which is a class defined within another class, and a subclass, which is a class defined by extending an existing class.
In Python, class inheritance (upon which the super method is based) is accomplished by defining a class with the super class provided as a parameter:
class Application(Frame):
... #Some class definition
class MyButton(Application):
... #MyButton is now a subclass of Application.
But this is not what you want, since you want to inherit the behaviour of the Tkinter Button
and Label
classes for your MyButton
and MyLabel
classes respectively (rather than inheriting the behaviour of the Application
class.
You original attempt using nested classes doesn't appear as necessarily a bad idea, since it would neatly package all of the behaviour of your class into one place, but it has serious drawbacks which probably aren't what you want.
For a start, you cannot reference an instance of the Application
class from the nested classes without injecting it in somehow, such as during initialisation. You can, however, access the properties if they are class properties, defined in the Application
class namespace, just like you nested classes. This is probably confusing so here is an example:
class Application(object):
classvar = "Foo" #This is a class level variable
class NestedClass(object):
#This is now a nested class, accessed using Application.NestedClass
def __init__(self, app):
#This will fail, classvar doesn't exist in this scope
self.var = classvar
#This will work if app is an instance of Application
#Or if app is the class itself
self.var = app.classvar
#This will always work, since it references the Application
#class directly but it won't capture changes introduced
#by an instance of Application, which is what you'll probably do
self.var = Application.classvar
Class level behaviour becomes very confusing due to scoping, and nested classes are even more confusing for nothing that can't be gained from implementing every class at the module level.
The best way to inject this kind of requirement is to do it the very way Tkinter
does it itself. Hand off the Application
instance as the master of the widget instance it creates. This is shown in Marcin's answer.
Upvotes: 0
Reputation: 53525
In the call to super()
you have to pass your type
and "yourself" (self):
so instead of doing:
super(Application, self)
you should do:
super(MyButton, self)
Hence the error, obj must be an instance or subtype of type
:
self
is not an instance nor subtype of Application
Upvotes: 0
Reputation: 238131
Nested class cant access directly attributes of outer class. You need to do it indirectly, for example:
class Application(Frame):
global yearcal
def __init__(self, master=None):
Frame.__init__(self, master)
self.month = 5
self.year = 2014
self.color_clicked = 'lightskyblue'
now = datetime.datetime.now()
self.thisyear = now.year
self.thismonth = now.month
self.today = now.day
self.textcolor = 'purple'
self.bgcolor = 'gray'
self.today_color = 'palegreen1'
self.apt_color = 'light coral'
# create button and label and pass the application instance
# so that they can reference its attributes and methods
self.my_button = MyButton(self)
self.my_label = MyLabel(self)
class MyButton(Button):
def __init__(self, app_instance, *args, **kwargs):
Button.__init__(self, *args, **kwargs)
self['bg'] = app_instance.backgroundcolor
self['fg'] = app_instance.textcolor
self['relief'] = FLAT
class MyLabel(Label):
def __init__(self, app_instance, *args, **kwargs):
Label.__init__(self, *args, **kwargs)
self['fg'] = app_instance.textcolor
Upvotes: 2
Reputation: 59601
So I have a class, Application, with 2 subclasses MyButton and MyLabel.
MyButton
and MyLabel
do not appear to be subclasses of Application
. You can only call super()
to access Application
from subclasses.
For example, to make MyLabel
a subclass of Application
class MyLabel(Application):
def __init__(self, *args, **kwargs):
...
Upvotes: 0