12

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.

4
  • 2
    you could have the subclass constructor call the superclass constructor via super stackoverflow.com/questions/576169/… Commented Oct 10, 2013 at 20:12
  • Thanks for the answer. The thing is, calling super, i would have only one constructor. In Java is possible to have more than one, if the number (and/or type) of arguments is different. I wonder if the same thing exists in python. Commented Oct 10, 2013 at 20:14
  • 1
    You can use @classmethod to make as many constructor-like methods as you want. Commented Oct 10, 2013 at 20:16
  • 1
    Specifically why do you need two constructors? You may want to look at class methods to simulate this behavior stackoverflow.com/a/141777/735204 Commented Oct 10, 2013 at 20:16

3 Answers 3

46

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Just for the record, __init__ is not the constructor, it's (as the name implies) an initializer. The proper constructor is__new__
@brunodesthuilliers: The documentation calls __init__ the constructor repeatedly (e.g., here). And that's consistent with other languages—e.g., in C++, the method with the same name as the class that takes initialization values is the constructor; the method that allocates storage and is called new is the allocator.
@brunodesthuilliers: When the docs are speaking carefully, "constructor" only refers to the call to the class object, which may end up calling __new__ and/or __init__, not to either of the methods. But when they're speaking carelessly, it's always __init__, not __new__, that's called a constructor.
the doc also use the terms "variable" and "assignment" instead of "name" and "binding", which BTW confuses the hell out of people coming from the C world. Also __new__ doesn't necessarily "allocates" any storage - it can return whatever you want it to return, including an already existing object.
@brunodesthuilliers: You can argue that the docs are badly worded. But saying "__init__ is not the constructor… The proper constructor is __new__…" is wrong. The docs call __init__ and not __new__ the constructor, and __init__ is the one that parallels what constructors in other languages do; you can't just redefine terms to mean something different from what everyone else means and then say "According to my idiosyncratic definitions, you're incorrect."
3

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()

Comments

0

There are the methods in the accepted answer, but I think this one is fairly flexible. It's convoluted, but very flexible.

When the class is instiated, init calls a method and pass it a string argument (obtained from instantiation). That function uses conditionals to call the right "constructor" function to initialize your values, let's say you have different sets of possible starting values.

If you need to provide other arguments (e.g. that might have a value only at runtime), you can use default values in init() to allow optional arguments, and initialize those in init as you normally would.

class MyClass:
def __init__(self,argsSet1, otherAttribute="Assigning this default value 
             to make this other argument optional",):
    self.selectArgSet(argsSet1)
    self.otherAttribute = otherAttribute
    print otherAttribute
def selectArgSet(self,ArgSet1):
    if ArgSet1 == "constructorArgSet1":
        self.constructorArgSet1()
    elif ArgSet1 == "constructorArgSet2":
        self.constructorArgSet2()
def constructorArgSet1(self):
    print "Use this method as Constructor 1"
    self.variable1 = "Variable1 value in Constructor 1"
    self.variable2 = "Variable2 value in Constructor 1"
    print self.variable1
    print self.variable2
def constructorArgSet2(self):
    print "Use this method as Constructor 2"


      self.variable1 = "Variable1 value in Constructor 2"
        self.variable2 = "Variable2 value in Constructor 2"
        print self.variable1
        print self.variable2

myConstructor_1_Instance = MyClass("constructorArgSet1")
myConstructor_2_Instance = MyClass("constructorArgSet2", "You can still 
                                           initialize values normally")

The output of which is:

Use this method as Constructor 1

Variable1 value in Constructor 1

Variable2 value in Constructor 1

Assign default value to make this other argument optional

Use this method as Constructor 2

Variable1 value in Constructor 2

Variable2 value in Constructor 2

You can still initialize values normally

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.