colossatr0n
colossatr0n

Reputation: 2355

Have subclass inherit non-default __init__ values from an instantiated main class

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

Answers (2)

abarnert
abarnert

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

Mad Physicist
Mad Physicist

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

Related Questions