ailoher
ailoher

Reputation: 71

Method belonging to an object from a class depending on attribute

My concern is related to one question posted here, but this time referred to Python language rather than C#.

I am aiming to use the same class to instantiate (two) different objects which share some methods, but not all of them. I came to the conclussion that the most efficient way to do so, if existing, might be to add an attribute which could give access to one or another set of methods depending on its value, while sharing the ones that are used for both cases. Is this actually possible in Python? If not, how would you recommend me to deal with this issue?

Thank you in advance, and best regards.

EDIT #1: I actually have one more small question regarding the use of Factory in this context, related to the use of more arguments and functions shared by the rest of the subclasses. Would this be the right way of defining my problem? Can 'init' and 'sharedFunction' methods be defined separate from the 'factory' one?

class Object:

    def __init__(self, serial, np, t):
        self.serial = serial
        self.np = np
        self.t = t

    # Factory method
    def factory(model): 
        if model == 'modelA':
            return ModelA()
        if model == 'modelB':
            return ModelB()

    # Shared function
    def sharedFunction(self):
        pass

class ModelA(Object):

    def function1(self):
        self.t.sleep(10)

So that later we can instantiate and use the objects as:

>>> modelA = Object.factory('modelA')
>>> modelA.function1()

Thanks a lot for your time.

EDIT #2 (after comment #9): There is still one thing which is not clear enough for me, concerning the definition of attributes within the superclass factory function. Is it mandatory to initialize with specific values or doing so just with the ones provided by the constructor (which is would make sense to me) would do the trick?

class Object(object):

    def __init__(self, serial, np, t):
        self.serial = serial
        self.np = np
        self.t = t

    # Factory method
    @staticmethod
    def factory(model): 
        if model == 'modelA':
            return ModelA(serial, np, t) # Here is where I am given an error message. Must I initialize the attributes of modelA and modelB with specific values? Why can't I do so for instance either with self.serial or just serial as I just created the constructor above?
        if model == 'modelB':
            return ModelB(serial, np, t) # Same as above

    # Shared function
    def sharedFunction(self):
        pass

class ModelA(Object):

    def __init__(self, serial, np, t, other_stuff):
        super(ModelA,self).__init__(serial, np, t)
        self.other_stuff = other_stuff

    def function1(self):
        self.t.sleep(10)

So that later we can instantiate and use the objects as:

>>> modelA = Object.factory('modelA', other_stuff)
>>> modelA.function1()

Upvotes: 1

Views: 1386

Answers (1)

Martin Frodl
Martin Frodl

Reputation: 657

What you are describing sounds very much like a factory. In its simplest form, it can be implemented in the following way:

class Animal:
    @staticmethod
    def factory(kind):
        if kind == 'Cat':
            return Cat()
        elif kind == 'Bird':
            return Bird()

class Cat(Animal):
    def say(self):
        return 'Meow'

class Bird(Animal):
    def say(self):
        return 'Chirp'

Now you can instantiate Animals using the factory() method which will automatically pick a subclass based on the kind parameter:

>>> bird = Animal.factory('Bird')
>>> bird.say()
'Chirp'

EDIT:

It is possible to define other methods in the base class, such as __init__() or sharedFunction(). However, to make the parent-class attributes (self.serial etc.) accessible to the subclass, the parent class constructor has to be called. This can be accomplished in two ways:

  1. Reuse the parent class constructor as is
  2. Override the constructor in subclasses and call the parent class constructor from it:

    class ModelA(Object):
        def __init__(self, serial, np, t, other_stuff):
            # Note: in Python 2, this requires `Object` to inherit from `object`
            super(ModelA, self).__init__(serial, np, t)
            self.other_stuff = other_stuff
    

In both cases, you have to pass the relevant arguments to the constructor when creating the object in factory(). In (1), this means you have to do something like:

if model == 'modelA':
    return ModelA(serial=42, np='p', t=0)

In (2), you have to provide any extra parameters you added:

if model == 'modelA':
    return ModelA(serial=42, np='p', t=0, other_stuff='something')

Also not that factory() has to be defined as @staticmethod in order to make it callable without a specific instance.

Upvotes: 1

Related Questions