pythonturtle-graphicspython-turtlepong

How can I solve the key error in this OOP turtle game?


I'm trying to do a Pong game using turtle to practice a little OOP. My objective here is to make the paddles and set their places.

There's two different files:

the main>

from turtle import Screen
from paddle import Paddle


screen = Screen()
screen.setup(width=800, height=600)
screen.bgcolor("blue")
screen.title("Pong Game")
screen.tracer(0)

r_paddle = Paddle((350, 0))
l_paddle = Paddle((-350, 0))

screen.update()

screen.listen()
screen.onkeypress(r_paddle.go_up, "Up")
screen.onkeypress(r_paddle.go_down, "Down")

screen.exitonclick()

and the Paddle file>

from turtle import Turtle


class Paddle(Turtle):

    def __int__(self, position):
        super().__init__()
        self.shape("square")
        self.color("white")
        self.shapesize(stretch_wid=5, stretch_len=1)
        self.penup()
        self.goto(position)

    def go_up(self):
        new_y = self.ycor() + 20
        self.goto(self.xcor(), new_y)

    def go_down(self):
        new_y = self.ycor() - 20
        self.goto(self.xcor(), new_y)

When I run it, an error appears: Key error.

I've tried to modify the code, put all in the same file, google somethings... Till now I really don't understand why it doesn't work.


Solution

  • Errors are good! More than just a KeyError, this error gives the exact line the exception occurred on and a stack trace of all function calls leading to the error:

    Traceback (most recent call last):
      File "/home/g/programming/test.py", line 11, in <module>
        r_paddle = Paddle((350, 0))
      File "/usr/lib/python3.10/turtle.py", line 3815, in __init__
        RawTurtle.__init__(self, Turtle._screen,
      File "/usr/lib/python3.10/turtle.py", line 2545, in __init__
        self.turtle = _TurtleImage(screen, shape)
      File "/usr/lib/python3.10/turtle.py", line 2488, in __init__
        self._setshape(shapeIndex)
      File "/usr/lib/python3.10/turtle.py", line 2502, in _setshape
        self._type = screen._shapes[shapeIndex]._type
    KeyError: (350, 0)
    

    Don't ignore this error. Always share it when you have a question about your code. What can be learned from this error? (350, 0) is being passed into the RawTurtle internal initializer and some code that has to do with shapes in the turtle library is raising. A possible next step is to minimize the problem. It can be reproduced with two lines of code that doesn't involve the Paddle class at all:

    from turtle import Turtle
    
    Turtle((350, 0))  # same KeyError
    

    The library is not liking this tuple, but it does seem to accept some optional parameter. What parameter does it actually expect? The docs reveal:

    class turtle.RawTurtle(canvas)

    class turtle.RawPen(canvas)

    Parameters

    canvas – a tkinter.Canvas, a ScrolledCanvas or a TurtleScreen

    We're not passing in a canvas. The intent is to pass that tuple to our Paddle initializer, which is not passing it along to super().__init__(). Weirdly, in the stack trace, we don't even see our Paddle constructor being invoked. Adding a print statement where control should flow to confirms this:

    class Paddle(Turtle):
        def __int__(self, position):
            print("This should print")
    

    Does this print? No. Examine the initializer again:

    def __int__(self, position):
    

    Looks like a typo: __init__ was intended rather than __int__. That's the fix! Paddle() was invoking the initializer from the superclass rather than our initializer, which didn't exist as far as Turtle was concerned due to the typo.

    However, since an ounce of prevention is worth a pound of cure, you'll save yourself a good deal of future stress if you avoid subclassing Turtle entirely. Always use composition, not inheritance with turtle. See this post for a detailed explanation. The error is much easier to debug with composition ("Paddle has a Turtle" rather than "Paddle is a Turtle"):

    Traceback (most recent call last):
      File "/home/greg/programming/test.py", line 11, in <module>
        r_paddle = Paddle((350, 0))
    TypeError: Paddle() takes no arguments
    

    Here's the code that produces the above, far clearer error:

    from turtle import Turtle
    
    
    class Paddle:
        def __int__(self, position):  # typo: should be __init__
            self.turtle = t = Turtle()
            t.shape("square")
            t.color("white")
            t.shapesize(stretch_wid=5, stretch_len=1)
            t.penup()
            t.goto(position)
    
        def go_up(self):
            t = self.turtle
            new_y = t.ycor() + 20
            t.goto(t.xcor(), new_y)
    
        def go_down(self):
            t = self.turtle
            new_y = t.ycor() - 20
            t.goto(t.xcor(), new_y)