What is a clean, Pythonic way to have multiple constructors in Python?

What is a clean, Pythonic way to have multiple constructors in Python?

Actually None is much better for magic values:

class Cheese():
    def __init__(self, num_holes = None):
        if num_holes is None:
            ...

Now if you want complete freedom of adding more parameters:

class Cheese():
    def __init__(self, *args, **kwargs):
        #args -- tuple of anonymous arguments
        #kwargs -- dictionary of named arguments
        self.num_holes = kwargs.get(num_holes,random_holes())

To better explain the concept of *args and **kwargs (you can actually change these names):

def f(*args, **kwargs):
   print args: , args,  kwargs: , kwargs

>>> f(a)
args:  (a,)  kwargs:  {}
>>> f(ar=a)
args:  ()  kwargs:  {ar: a}
>>> f(1,2,param=3)
args:  (1, 2)  kwargs:  {param: 3}

http://docs.python.org/reference/expressions.html#calls

Using num_holes=None as the default is fine if you are going to have just __init__.

If you want multiple, independent constructors, you can provide these as class methods. These are usually called factory methods. In this case you could have the default for num_holes be 0.

class Cheese(object):
    def __init__(self, num_holes=0):
        defaults to a solid cheese
        self.number_of_holes = num_holes

    @classmethod
    def random(cls):
        return cls(randint(0, 100))

    @classmethod
    def slightly_holey(cls):
        return cls(randint(0, 33))

    @classmethod
    def very_holey(cls):
        return cls(randint(66, 100))

Now create object like this:

gouda = Cheese()
emmentaler = Cheese.random()
leerdammer = Cheese.slightly_holey()

What is a clean, Pythonic way to have multiple constructors in Python?

One should definitely prefer the solutions already posted, but since no one mentioned this solution yet, I think it is worth mentioning for completeness.

The @classmethod approach can be modified to provide an alternative constructor which does not invoke the default constructor (__init__). Instead, an instance is created using __new__.

This could be used if the type of initialization cannot be selected based on the type of the constructor argument, and the constructors do not share code.

Example:

class MyClass(set):

    def __init__(self, filename):
        self._value = load_from_file(filename)

    @classmethod
    def from_somewhere(cls, somename):
        obj = cls.__new__(cls)  # Does not call __init__
        super(MyClass, obj).__init__()  # Dont forget to call any polymorphic base class initializers
        obj._value = load_from_somewhere(somename)
        return obj

Leave a Reply

Your email address will not be published.