2025, Nov 13 15:02
Почему наследование от turtle.Screen даёт TypeError и как исправить через _Screen
Разбираем, почему в Python наследование от turtle.Screen даёт TypeError: Screen — функция. Исправление через _Screen и альтернатива с композицией Screen.
Наследование от turtle.Screen приводит к ошибке “TypeError: function() argument 'code' must be code, not str” — и дело не в логике вашей игры. Причина проще: в turtle Screen — это не класс для наследования, а функция, возвращающая экземпляр внутреннего класса-реализации. Если пытаться наследоваться от функции, Python закономерно возражает.
Постановка задачи
Рассмотрим минимальный каркас в стиле Pong, разделённый на два файла. Проблема возникает именно из‑за наследования от Screen.
Точка запуска:
from arena import Stage
from paddle import Paddle
from orb import Orb
from tally import Tally
ARENA_W = 600
ARENA_H = 500
PAD_SIZE = 50
field = Stage(ARENA_W, ARENA_H, pad_user, pad_cpu, tally_user, tally_cpu, orb)
pad_user = Paddle(ARENA_W, ARENA_H, PAD_SIZE)
pad_cpu = Paddle(ARENA_W, ARENA_H, PAD_SIZE)
tally_user = Tally(ARENA_W, ARENA_H)
tally_cpu = Tally(ARENA_W, ARENA_H)
orb = Orb()
running = True
while running:
field.bat_orb_touch()
И вот обёртка экрана:
from turtle import Screen, Turtle
class Stage(Screen):
def __init__(self, w, h, pad_u, pad_c, sc_u, sc_c, orb):
super().__init__()
self.w = w
self.h = h
self.pad_u = pad_u
self.pad_c = pad_c
self.sc_u = sc_u
self.sc_c = sc_c
self.orb = orb
self.bgcolor("black")
self.screensize(w, h)
draw_center_line()
def draw_center_line(self):
center = Turtle()
center.pensize(20)
center.pencolor("white")
center.penup()
center.goto(0, self.h-10)
center.setheading(270)
center.pendown()
for step in range(self.h/(2*10)):
center.forward(10)
if cen_line.pencolor() == 'white':
cen_line.pencolor('black')
else:
cen_line.pencolor('white')
def bat_orb_touch(self, bat):
return all([abs(orb.xcor()-bat.xcor()) < 10, abs(orb.ycor()-bat.ycor()) < 15])
Почему это падает
Ошибка возникает на строке определения класса, где Stage пытается унаследоваться от Screen. В turtle Screen — не класс, а функция. Эта функция конструирует и возвращает экземпляр внутреннего класса. Попытка записать class Stage(Screen): в такой ситуации заканчивается именно той ошибкой, которую вы видите, потому что Python ожидает в списке базовых типов класс (или совместимый тип), а не функцию.
Внутренний класс, который действительно реализует окно, называется _Screen. Если вам нужны именно механики наследования, наследоваться следует от него.
Исправление
Используйте внутренний класс, лежащий в основе Screen. Наследование должно быть от _Screen, а не от Screen.
from turtle import _Screen, Turtle
class Stage(_Screen):
def __init__(self, w, h, pad_u, pad_c, sc_u, sc_c, orb):
super().__init__()
self.w = w
self.h = h
self.pad_u = pad_u
self.pad_c = pad_c
self.sc_u = sc_u
self.sc_c = sc_c
self.orb = orb
self.bgcolor("black")
self.screensize(w, h)
draw_center_line()
def draw_center_line(self):
center = Turtle()
center.pensize(20)
center.pencolor("white")
center.penup()
center.goto(0, self.h-10)
center.setheading(270)
center.pendown()
for step in range(self.h/(2*10)):
center.forward(10)
if cen_line.pencolor() == 'white':
cen_line.pencolor('black')
else:
cen_line.pencolor('white')
def bat_orb_touch(self, bat):
return all([abs(orb.xcor()-bat.xcor()) < 10, abs(orb.ycor()-bat.ycor()) < 15])
Это изменение устраняет конкретную ошибку типов, вызванную попыткой наследоваться от функции. Остальная логика остаётся прежней.
Почему эта деталь важна
turtle предоставляет Screen как фабричный входной пункт, тогда как реальный класс-реализация — _Screen. Понимание этого избавляет от запутанных ошибок на этапе наследования. Есть и более общий архитектурный вывод, часто уместный в подобных случаях: предпочитайте композицию наследованию в конструкциях turtle — контейнер игры имеет Screen, а не является Screen.
Выводы
Если базовый «класс» вызывает TypeError прямо в объявлении класса, проверьте, от чего вы наследуетесь. Быстрая проверка типа символа перед использованием — хороший sanity‑тест. Если решите остаться с наследованием для оболочки окна, наследуйтесь от _Screen. Если хотите держаться публичной поверхности, строите систему вокруг экземпляра Screen и компонуйте объекты вокруг него. И наконец, изолируя подобные ошибки, сводите код к минимальному воспроизводимому примеру — так проще быстро найти точку сбоя и не гоняться за несвязанными частями.