Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple constructors in python, using inheritance

I have a class AbstractDataHandle, whith his init method, and a class Classifier. I would like to have two constructors in Classifier, Java like. One inherited from it`s superclass, and one brand new.

It would be something like (but i intend to "keep" the two constructors):

class AbstractDataHandle():
    def __init__(self, elements, attributes, labels):
        self._load(elements, attributes, labels)


class Classifier(AbstractDataHandle):
    def __init__(self, classifier="LinearSVC", proba=False):
        self._fit(classifier, proba)

Can i have two constructors in one class? If yes, can i have a constructor inherited from a superclass, and add a new one?

Thank you in advance.

like image 308
Lucas Ribeiro Avatar asked Oct 10 '13 20:10

Lucas Ribeiro


2 Answers

You can't have two constructors in one class.

Constructors have to be named __init__. And, unlike Java, Python doesn't allow overloading functions or methods by the type of their arguments. So, if you had two constructors, they would both be the same function.

There are a few ways around this.


Use @classmethods as alternate constructors:

class Breakfast(object):
    @classmethod
    def from_eggs(cls, eggs):
        obj = cls()
        obj.spam, obj.eggs = 5, eggs
        return obj

    @classmethod
    def from_spam_and_eggs(cls, spam, eggs):
        obj = cls()
        obj.spam, obj.eggs = spam, eggs
        return obj

A simple example from the standard library is datetime.datetime, which can be constructed with now, fromtimestamp, or a few other alternate constructors, besides the default.


Use default-valued, keyword-only, and/or variable-argument parameters to make a single constructor that can be called different ways:

class Breakfast(object):
    def __init__(self, eggs=0, spam=5):
        self.spam, self.eggs = spam, eggs

int is an example of this: You can create it from a string and a base, or from a single argument that knows how to convert itself to an integer.


Create subclasses that each have different constructors:

class Breakfast(object):
    pass

class HealthyBreakfast(object):
    def __init__(self, spam):
        self.spam, self.eggs = spam, 0

class NormalBreakfast(object):
    def __init__(self, spam, eggs):
        self.spam, self.eggs = spam, eggs

In any of these cases, you can factor out commonalities into a single "base" initializer. For example:

class Breakfast(object):
    def __init__(self, eggs, spam):
        self.spam, self.eggs = spam, eggs

class HealthyBreakfast(object):
    def __init__(self, spam):
        super(HealthyBreakfast, self).__init__(0, spam)

Of course in no case is it possible to have breakfast without spam.

like image 109
abarnert Avatar answered Nov 08 '22 01:11

abarnert


You can use class methods, which work as factory methods. That's imho the best approach for multiple constructors. First argument 'cls' is class itself, not it's instance, so cls('Truck') in class method invokes constructor for class Car.

class Car(object):
    def __init__(self, type='car'):
        self.car_type = type

    @classmethod
    def Truck(cls):
        return cls('Truck')

    @classmethod
    def Sport(cls):
        return cls('Sport')

    @classmethod
    def Van(cls):
        return cls('Van')

Then you call factory method this way:

mycar = Car.Sport()
like image 23
Pawel Bragoszewski Avatar answered Nov 08 '22 02:11

Pawel Bragoszewski