How to create a subclass in python that is inherited from turtle Module

Question:

So, i’m trying to learn python and every time i post a question here it feels like giving in…

I’m trying to make my own class of turtle.Turtle.

    import turtle
class TurtleGTX(turtle.Turtle):
    """My own version of turtle"""
    def __init__(self):
        pass

my_turtle = TurtleGTX()
my_turtle.forward(10)

Gives the Traceback: AttributeError: ‘TurtleGTX’ object has no attribute ‘_position’. Which I then learn is a “private vairable” which according to the offical python tutorial i can mangle/override in my subclass TurtleGTX. How to do this with a program as large as turtle seems rather difficult and implies i’m missing a simpler solution to the problem. In the end i learned and that was the point but i would still like to run it by the community to see if there is a elegant way to create a subclass of turtle.Turtle. (The next step is to have your turtle behave different then the standard turtle)

So a comment below made me think that maybe i could do this:

import turtle
class TurtleGTX(turtle.Turtle):
    """My own version of turtle"""


my_turtle = TurtleGTX()
my_turtle.forward(100)

which actual runs! Now i’m going to see where that leads me… something tells me that i might have gone 1 step forward two step back as this means i won’t be able to initialize anything on my subclass…

Asked By: Drew Verlee

||

Answers:

If you redefine a method (such as __init__()) in a child class then it is your responsibility to call the parent’s method in order to have the parent’s behavior respected.

Rounding up Ignacio’s answer and orokusaki’s comment you probably should write something like

import turtle
class TurtleGTX(turtle.Turtle):
    """My own version of turtle"""
    def __init__(self,*args,**kwargs):
        super(TurtleGTX,self).__init__(*args,**kwargs)
        print("Time for my GTX turtle!")

my_turtle = TurtleGTX()
my_turtle.forward(100)
Answered By: Odomontois

It’s a tempting pattern to subclass Turtle and add custom functionality, say, turtle.jump(). But I’ve seen a good deal of problems caused by this pattern and caution against it.

Calling the Turtle() initializer (including subclasses of Turtle) registers the object with the turtle module’s internal list of turtles. This list has _update() called on it per frame if you don’t disable the internal update loop with turtle.tracer(0). This internal turtle isn’t likely to get garbage collected as your subclass might expect.

In addition to the update/draw internals they’re hooked into, Turtle has many properties and methods that can easily name clash with your custom properties and methods (there are about 150 such names in the turtle module, not counting dunderscores). When calling, say, self.left(), it can be hard to remember if this is a turtle method call on the superclass or your derived class. By composing the turtle as a property rather than a subclass, self.turtle.left() makes the ownership completely clear, at the cost of a bit of verbosity.

Here’s a collection of alternatives to inheritance, some of which are only useful for specific purposes but listed here anyway for completeness:

  • If you don’t mind the turtles not being garbage collected (you are making a fixed amount that you plan to keep around), you could allocate instances of a custom class, each of which has an internal self.turtle = Turtle() instance that is manipulated in the normal way from the wrapper. This is the composition approach.

    • Since you’re probably only using a handful of turtle methods, you can compromise a bit and add a self.left(n) method on your composed class and delegate to the underlying self.turtle.left(n). This involves adding a few extra methods but avoids all of the pitfalls of inheritance.
  • Instead of classes, you could make Turtle instances and pass them to functions that cause them to take an action in a C-style imperative manner: def jump(turtle, height): ....

  • If you plan to create particles of some sort that are created and destroyed relatively frequently and you just need a turtle to render rather than represent them, you might store the particles’ internal representations and physics properties in a class alongside a reference to a single "pen" turtle. When drawing is needed, tracing is disabled and the turtle is moved from one position to the next among all shared particles, drawing as needed.

    In theory, this is a great solution, but in practice, I’ve found it to be too much of a performance impact to bear, even with tracer off.

  • Custom classes can borrow from an object pool of turtles, helping to mitigate the garbage collection problem. See Why is my Python Turtle program slowing down drastically the longer it runs? for details.

That said, I’d be eager to see a useful, non-trivial case of the subclassing pattern if anyone has one as a counterargument.

Answered By: ggorlen