Torilla
Torilla

Reputation: 403

Python class interdependencies

I have a python class that serves as a baseclass for further subclasses. It contains a methods that should act on all subclass the same, e.g. I want to put it in the base class. The problem is, that this method should return a new instance of the subclass. But I since the baseclass is located before the definition of the subclass, I can not create a new instance of the subclass, as it is not known in the scope of the baseclass:

class Base:
  def __init__(self, value):
    self.value = value

  def convert_child_classes(self, newclass):
    newvalue = MakeUsableInNewclass(self.value)
    newattr = MakeUsableInNewclass(self.subclassattr)
    return newclass(newattr, newvalue)


class Child1(Base):
  def __init__(self, subclassattr, value)
    super(Child, self).__init__(value)
    self.subclassattr = subclassattr

  def MethodForSubClassAttr(self):
    ...do sth with self.subclassattr...


class Child2(Base):
  def __init__(self, subclassattr, value)
    super(Child, self).__init__(value)
    self.subclassattr = subclassattr

  def SomeOtherSubClassAttrMethod(self):
    ...do sth that is related to this class attr...

I if I have an instance of Child1 I want to be able to do some stuff with its data and then return an instance of the Child2 with the new values when calling convert_child_classes(Child2):

A = Child1('someattr', 5)
B = A.convert_child_classes(Child2)

now B should be an instance of Child2 with a value that was calculated form Child1. But since Base class does now know what Child1 or Child2 is, it can not initiate the new class.

Upvotes: 0

Views: 444

Answers (2)

Luan Naufal
Luan Naufal

Reputation: 1424

I got your problem:
1. Actually you're using Child in the super and it's wrong, as it should be the name of the class you're operating on, in this case Child1 or Child2.
2. I'd add Base as an abstract class, to ensure it won't be instantiated (as I got from your question it's the case).
3. since the method MakeUsableInNewClass is mandatory to be implemented, I'd add as an abstractmethod to ensure implementation on the Child ones.

So the correct code would be:

from abc import ABC, abstractmethod
class Base(ABC):
    def __init__(self, value):
        self.value = value

    def convert_child_classes(self, newclass):
        newvalue, newattr = self.MakeUsableInNewclass()
        return newclass(newattr, newvalue)

    @abstractmethod
    def MakeUsableInNewclass(): pass

class Child1(Base):
    def __init__(self, subclassattr, value):
        super(Child1, self).__init__(value)
        self.subclassattr = subclassattr

    def MakeUsableInNewclass(self):
        newvalue = self.value #do operations
        newattr = self.subclassattr #do operations
        return newvalue, newattr

class Child2(Base):
    def __init__(self, subclassattr, value):
        super(Child2, self).__init__(value)
        self.subclassattr = subclassattr

    def MakeUsableInNewclass(self):
        newvalue = self.value #do operations
        newattr = self.subclassattr #do operations
        return newvalue, newattr

Upvotes: 1

snakecharmerb
snakecharmerb

Reputation: 55669

Something like this ought to work (untested):

class Measurement:

    @classmethod
    def from_other(cls, other):
        base = other.convert_to_base_unit()
        converted = cls.base_to_unit(base)
        return cls(converted)

    @classmethod
    def base_to_unit(cls, value):
        # Let the subclass implement this
        raise NotImplementedError

    def convert_to_base_unit(self):
        # Let the subclass implement this
        raise NotImplementedError

Implemented this way, the base class doesn't need to know anything about the subclasses. The base class provides the template method (from_other) and the subclasses provide the implementation.

Upvotes: 1

Related Questions