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.
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)