Mate de Vita
Mate de Vita

Reputation: 1325

Python: Constructing a multiple-inheritance subclass instance from a superclass

So I have in my project two classes: Circuit and SubCircuit. At some point I may need to construct a SubCircuit from a Circuit. Is there a more elegant way to do that than what's done below in the last 4 lines? Circuit may get some new attributes at some point for example, which would mean that conversion would also need to be updated - basically inviting bugs.

class Gate(abc.ABC):
    def __init__(self, size):
        self.in_ports = (InPort(self),) * size
        self.out_ports = (OutPort(self),) * size


class Circuit:
    def __init__(self, size):
        self.input = (OutPort(self),) * size
        self.output = (InPort(self),) * size
        self.gates = []

    # ... some other stuff that messes around with these attributes


class SubCircuit(Gate, Circuit):
    def __init__(self, circuit=None):
        Gate.__init__(self, size)
        Circuit.__init__(self, size)

        if circuit is not None:
            self.gates = circuit.gates
            self.input = circuit.input
            self.output = circuit.output

Upvotes: 1

Views: 270

Answers (1)

jsbueno
jsbueno

Reputation: 110271

Bugs are already there - when you do self.gates = circuit.gates, circuit.gates being a list, yu point both references to the same list - and if this list is updated on the original circuit, this update will be reflected in your subcircuit instance.

I think the most sane pattern tehre is to have an alternate constructor for the class if you have a circuit instance from which to update your own:

from copy import copy
class SubCircuit(Gate, Circuit):
    def __init__(self, size):
        Gate.__init__(self, size)
        Circuit.__init__(self, size)

    @classmethod
    def from_circuit(cls , circuit, size):
        self = SubCircuit(size)
        for key, value in circuit.__dict__.items():
             setattr(self, key, copy(value))
        return self

One "right" thing to do is to make the classes __init__ and other methods calling each other through the collaborative use of super() instead of calling then explicitly by name - however, if your classes and subclasses are fixed to these 3, that may be a bit overkill, because Python's objects not handling extra parameters passed to its own __init__ method. (So, you'd have to verify in your base classes __init__ if they are the last ones prior to object on the Method Resolution Order, and swallow the remaining args)

Upvotes: 1

Related Questions