Reputation: 2355
How can I have a subclass that inherits not just __init__
variables from the main class, but also inherits the instantiated values from an instantiated main class.
For example, say I have these classes:
class MainClass(object):
def __init__(self, mainVar1=None, mainVar2=None):
self.mainVar1 = mainVar1
self.mainVar2 = mainVar2
class SubClass(MainClass):
def __init__(self):
super(SubClass, self).__init__()
self.subVar1 = -1
And I do this:
main = MainClass(mainVar1=1, mainVar2=2)
sub = SubClass()
print(sub.mainVar1)
This prints out None
and not 1
because sub
calls the __init__
of MainClass
in which mainVar1
by default is set to None
.
What I'd like to do is instantiate SubClass
in such a way that it gets the input values used to instantiate MainClass
, so that print(sub.mainVar1)
prints 1
instead of None
.
I want to do this without repeating the same variables when instantiating the classes:
main = MainClass(mainVar1=1, mainVar2=2)
# This is what I'm trying to avoid.
sub = SubClass(mainVar1=1, mainVar2=2)
print(sub.mainVar1)
Is this possible? Is this a terrible design choice? What's the best way to do this?
EDIT:
Concrete Example
I have a class called ServerTools
that provides functions for accessing data on a server. This is my MainClass
class in the example above. To instantiate this class I need a username
, password
, and server_url
.
I then have a subclass called Docs
that creates a document from data on the server. To instantiate this class I need username
, password
, server_url
, and some other arguments. This subclass needs the functions from the main class ServerTools
to access data on the server.
My thought process was to have Docs
be a tool in ServerTools
, in which a document cannot be created without instantiating ServerTools
. I'm not sure whether Docs
should be a subclass, an inner-class, or something else entirely.
Upvotes: 0
Views: 204
Reputation: 365617
For your actual design, it sounds like you don't want subclasses at all.
Think about your object model in terms of the actual objects you're modeling, and the relationships between them, and it's usually clearer how the classes should be written.
You have a ServerTools
class. Instances of this class represent a server, or a connection to a server, or something like that.
You have a Docs
class. Instances of this class represent documents on a server.
Each Docs
object is not a server, so it should not be a ServerTools
instance. But each Docs
object has a server that it's stored on, so it should have a ServerTools
object.
So, you probably want to model it like this:
class ServerTools(object):
def __init__(self, username, password, server_url):
self.username = username
self.password = password
self.server_url = server_url
class Docs(object):
def __init__(self, server, path):
self.server = server
self.path = path
myserver = ServerTools('me', 'swordfish', 'smb://chico.example.com')
mydocs = Docs(myserver, '/Horse/Feathers')
Alternatively, if you rarely have a need for ServerTools
objects on their own, and want to create one for each Docs
object, you might create it in the initializer. To do that, you'd take all of the relevant ServerTools
-construction arguments as parameters:
class Docs(object):
def __init__(self, username, password, url, path):
self.server = ServerTools(username, password, url)
self.path = path
mydocs = Docs('me', 'swordfish', 'smb://chico.example.com' '/Horse/Feathers')
As a side note, I'm not sure why you wanted these arguments to have default values of None
. Why would you want to create a ServerTools
with no server_url
? So, I left the defaults off. But you can add them back on if you have a reason to use them.
Upvotes: 1
Reputation: 114230
You can pass through arguments using splat and splatty splat operators:
class SubClass(MainClass):
def __init__(self, *args, **kwargs):
super(SubClass, self).__init__(*args, **kwargs)
self.subVar1 = -1
sub = SubClass(mainVar1=1, mainVar2=2)
Remember that sub
is an instance of MainClass
by inheritance: isinstance(sub, MainClass)
will return True
. You do not need a separate instance of MainClass
at all.
As an extended example, even if you had a method called meth1
in MainClass
and overrode it in SubClass
, you can still call it like this:
MainClass.meth1(sub, ...)
Upvotes: 1