Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor specialization in python

Class hierarchies and constructors are related. Parameters from a child class need to be passed to their parent.

So, in Python, we end up with something like this:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        # do something with a, b, c, ka, kb, kc

class Child(Parent):
    def __init__(self, a, b, c, d, e, f, ka=None, kb=None, kc=None, kd=None, ke=None, kf=None):
        super(Child, self).__init__(a, b, c, ka=ka, kb=kb, kc=kc)
        # do something with d, e, f, kd, ke, kf

Imagine this with a dozen child classes and lots of parameters. Adding new parameters becomes very tedious.

Of course one can dispense with named parameters completely and use *args and **kwargs, but that makes the method declarations ambiguous.

Is there a pattern for elegantly dealing with this in Python (2.6)?

By "elegantly" I mean I would like to reduce the number of times the parameters appear. a, b, c, ka, kb, kc all appear 3 times: in the Child constructor, in the super() call to Parent, and in the Parent constructor.

Ideally, I'd like to specify the parameters for Parent's init once, and in Child's init only specify the additional parameters.

I'd like to do something like this:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        print 'Parent: ', a, b, c, ka, kb, kc

class Child(Parent):
    def __init__(self, d, e, f, kd='d', ke='e', kf='f', *args, **kwargs):
        super(Child, self).__init__(*args, **kwargs)
        print 'Child: ', d, e, f, kd, ke, kf

x = Child(1, 2, 3, 4, 5, 6, ka='a', kb='b', kc='c', kd='d', ke='e', kf='f')

This unfortunately doesn't work, since 4, 5, 6 end up assigned to kd, ke, kf.

Is there some elegant python pattern for accomplishing the above?

like image 615
Mark Visser Avatar asked Jul 29 '09 20:07

Mark Visser


People also ask

What is __ init __ constructor in Python?

The __init__ method is the Python equivalent of the C++ constructor in an object-oriented approach. The __init__ function is called every time an object is created from a class. The __init__ method lets the class initialize the object's attributes and serves no other purpose. It is only used within classes.

What is the special method for class constructor in Python?

To run the first step, Python classes have a special method called . __new__() , which is responsible for creating and returning a new empty object. Then another special method, . __init__() , takes the resulting object, along with the class constructor's arguments.

How are constructors in Python defined?

Python Constructor. A constructor is a special type of method (function) which is used to initialize the instance members of the class. In C++ or Java, the constructor has the same name as its class, but it treats constructor differently in Python. It is used to create an object. Constructors can be of two types.

What does __ add __ do in Python?

__add__ magic method is used to add the attributes of the class instance. For example, let's say object1 is an instance of a class A and object2 is an instance of class B and both of these classes have an attribute called 'a', that holds an integer.


2 Answers

"dozen child classes and lots of parameters" sounds like a problem irrespective of parameter naming.

I suspect that a little refactoring can peel out some Strategy objects that would simplify this hierarchy and make the super-complex constructors go away.

like image 180
S.Lott Avatar answered Sep 28 '22 22:09

S.Lott


Well, the only solution I could see is using a mixture of listed variables as well as *args and **kwargs, as such:

class Parent(object):
    def __init__(self, a, b, c, ka=None, kb=None, kc=None):
        pass

class Child(Parent):
    def __init__(self, d, e, f, *args, kd=None, ke=None, kf=None, **kwargs):
        Parent.__init__(self, *args, **kwargs)
        pass

This way, you could see which parameters are required by each of the classes, but without having to re-type them.

One thing to note is that you lose your desired ordering (a, b, c, d, e, f) as it becomes (d, e, f, a, b, c). I'm not sure if there's a way to have the *args before the other non-named parameters.

like image 36
Adam Avatar answered Sep 28 '22 22:09

Adam