someguy
someguy

Reputation: 314

How to make a class inherit from any object in Python

Summary:

I want to create a class that receives an object in init and becomes that object plus some extra functions that the class has. For example, the Flexible class:

class Flexible():
    def __init__(self, obj):
        self.obj = obj

    def be_flexible(self):
        print("Do something")

car = Flexible(Car('BMW'))
plane = Flexible(Plane('Boeing 747'))
car.drive()
car.park()
car.be_flexible()
plane.fly()
plane.be_flexible()

Details:

I have a Shape class and many Shapes that inherit from this class.

class Shape():
    def __init__(self, x, y, color=(0, 0, 0)):
        self.x, self.y = x, y
        self.anchor_x, self.anchor_y = 0, 0
        self.rotation = 0
        self.color = color

class Circle(Shape):
    def __init__(self, x, y, r, **kwargs):
        super().__init__(x, y, **kwargs)
        self.r = r

class Rectangle(Shape):
    def __init__(self, x, y, w, h, **kwargs):
        super().__init__(x, y, **kwargs)
        self.w = w
        self.h = h

class Triangle(Shape):
    def __init__(self, x, y, x2, y2, x3, y3, **kwargs):
        super().__init__(x, y, **kwargs)
        self.x2 = x2
        self.y2 = y2
        self.x3 = x3
        self.y3 = y3

The above code is simplified, all objects contain getters, setters, and various methods to change the shapes.

I want to add a method toggle_anchor(), to show/hide the anchor point. All shapes should be able to access this method. Normally I would add this in the class Shape, but these classes come from an external library, so I cannot modify it.

Therefore, I was hoping I could do something like this (note, AnchorShape has a Circle inside, which would be plotted to show where the shape's anchor point is):

class AnchorShape():
    def __init__(self, object):
        self.object = object
        self.anchor_shape = Circle(self.object.anchor_x + self.object.x,
                                   self.object.anchor_y + self.object.y, 1)

    def toggle_anchor(self):
        ...

where the following code will work:

circle = AnchorShape(Circle(x, y, r))
print(f"Created circle (radius:{circle.r}")
square = AnchorShape(Rectangle(x, y, s, s))
print(f"Created square (side:{square.w})")
circle.toggle_anchor()
square.toggle_anchor()

I am open to other ways to do this, I just want to be able to use shapes as normal with the new functionality.

I am trying to avoid doing the following, as this involves heavy code duplication:

class AnchorCircle(Circle):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.anchor_shape = Circle(self.anchor_x + self.x,
                                   self.anchor_y + self.y, 1)

    def toggle_anchor(self):
        ...

class AnchorRectangle(Rectangle):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.anchor_shape = Circle(self.anchor_x + self.x,
                                   self.anchor_y + self.y, 1)

    def toggle_anchor(self):
        ...

class AnchorTriangle(Triangle):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.anchor_shape = Circle(self.anchor_x + self.x,
                                   self.anchor_y + self.y, 1)

    def toggle_anchor(self):
        ...

Edit1: correct typos and added more details.

Upvotes: 0

Views: 330

Answers (1)

jsbueno
jsbueno

Reputation: 110301

What you are asking is one thing. What you describe as your needs is another thing.

What you really say you need can be resolved with multiple-inheitrance and no code redundancy - if you are only to review certain concepts.

Just create an AnchorShape class, which takes the new needed parameters, and keep using "super" as you are using, and then use multiple-inheirtance, with class declarations and empty bodies, to declare your specific classes:

class AnchorShape(Shape):
    def __init__(self, *args, anchor_x=None, anchor_y=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.anchor_shape = Circle(self.anchor_x + self.x,
                                   self.anchor_y + self.y, 1)

    def toggle_anchor(self):
        ...

class AnchorCircle(Circle, AnchorShape):
    pass

class AnchorRectangle(Rectangle, AnchorShape):
   pass

# and so on

Your question is about creating dynamic classes from objects (not from their classes) - that would be possible, but using a factory function (not a class), that would make a call to type to create a class programmatically and then return an instance of that new class. But it really seems it is not your actual use case.

Upvotes: 1

Related Questions