qwertz
qwertz

Reputation: 76

Subclassing, inheriting and subclass picking

I would like to build a class and subclasses where the subclasses inherit some methods and from the superclass.

Nothing special so far, but I would like to be able to create subclasses depending on a parameter e.g. a = Shape(sides=3, base=2, height=12) which should result in the same as c = Triangle(base=2, height=2) in the sample code:

class Shape:
    def __new__(cls, sides, *args, **kwargs):
        if sides == 3:
            print('a')
            return Triangle(*args, **kwargs)
        else:
            return Square(*args, **kwargs)

    def __init__(self, a):
        self._a = a

    @property
    def a(self):
        return self._a


class Triangle(Shape):
    def __init__(self, base, height):

        super().__init__(self, a='triangle')
        self.base = base
        self.height = height

    def area(self):
        return (self.base * self.height) / 2


class Square(Shape):
    def __init__(self, length):
        Shape.__init__(self, a='square')
        self.length = length

    def area(self):
        return self.length * self.length


a = Shape(sides=3, base=2, height=12)
b = Shape(sides=4, length=2)

c = Triangle(base=2, height=2)

print(c.a)

print(str(a.__class__))
print(a.area())

print(str(b.__class__))
print(b.area())

Which throws an error TypeError: __new__() missing 1 required positional argument: 'sides'.

when I do not inherit the class (do class Triangle:) it down not throw the error but of course I cannot use the function a anymore...

Any hints? My solutions so far were based on https://stackoverflow.com/a/60769071, https://stackoverflow.com/a/61509283 and https://www.code-learner.com/how-to-use-python-new-method-example/

One possibility is maybe the use of a Factory pattern but I really liked the idea of overwriting the new function...

Upvotes: 1

Views: 1201

Answers (2)

MukeshRKrish
MukeshRKrish

Reputation: 1090

You are inheriting the Shape class in the Triangle & Square classes, which will result in infinite recursive calls to __new__ of Shape class.

Have modified your code a little with a Factory class to achieve it.

class Shape:
    def __init__(self, a):
        self._a = a

    @property
    def a(self):
        return self._a

class ShapeFactory:
    def __new__(cls, sides, *args, **kwargs):
        if sides == 3:
            print('a')
            return Triangle(*args, **kwargs)
        else:
            return Square(*args, **kwargs)


class Triangle(Shape):
    def __init__(self, base, height):

        super().__init__(a='triangle')
        self.base = base
        self.height = height

    def area(self):
        return (self.base * self.height) / 2


class Square(Shape):
    def __init__(self, length):
        Shape.__init__(self, a='square')
        self.length = length

    def area(self):
        return self.length * self.length


a = ShapeFactory(sides=3, base=2, height=12)
b = ShapeFactory(sides=4, length=2)

c = Triangle(base=2, height=2)

print(c.a)

print(str(a.__class__))
print(a.area())

print(str(b.__class__))
print(b.area())

Upvotes: 2

Lcj
Lcj

Reputation: 451

Your Triangle class is inheriting the __new__ method of its superclass Shape which requires the side argument. You could either override this method in each subclass or make a new Factory class ShapeFactory which returns different shapes.

Upvotes: 1

Related Questions