0

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.

5
  • You are calling Circle inside AnchorRectangle and AnchorTriangle in the last part of the snippet. Are they typos? Also, I wonder why the Circle is called with two arguments, while the definition requires three positional arguments (x,y,r). Commented Oct 21, 2021 at 10:22
  • The Circle inside AnchorShapes is used to plot the anchor point. So an AnchorShape will always have a Shape and a Circle to show the anchor location. Also, I added the 3rd argument to Circle, that was a typo. Commented Oct 21, 2021 at 10:29
  • Maybe i didn't get your problem right or if i did just make a new class and add that common functionality to it and make the other classes inherit from the new one too. Commented Oct 21, 2021 at 10:39
  • @AjaySinghRana, I would do that but I am using an already existing library (pyglet), and I want to add anchor points to pyglet.shapes. Therefore, I cannot make changes to those classes, as they are part of an installed library (pip install pyglet), so I cannot "make the other classes inherit from the new one". Commented Oct 21, 2021 at 10:56
  • you didn't get me dude just try making a new class class Feautre(pyglet.shapes) and then add the feature you want and inherit from this class.By the way wait until someone answers or you might end up ruining the code. Commented Oct 21, 2021 at 10:59

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I ended up rewriting everything, but this looks like it is a step in the right direction. Still it does not work: let's say I can do Rectangle.height, I will not be able to run AnchorRectangle.height unless I create the attribute height in AnchorShape, but that does not make sense for AnchorCircle which does not have a height attribute, only radius.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.