Changes since Python 2.6 (turtle)

2025-06-06

Python 2.6以降のturtleモジュールにおける主な変更点や特徴について説明します。

Python 2.6 での turtle モジュールの位置づけ

Python 2.6は、Python 3.0への移行を助けるための過渡的なリリースでした。このバージョンで、turtleモジュールは大幅に強化され、標準ライブラリの新しいモジュールとして追加されました。それ以前のPythonバージョンにも類似の機能を提供するものはありましたが、2.6で現在のturtleモジュールの基盤が確立されたと言えます。

    • Python 2.6から、turtleモジュールはより洗練されたオブジェクト指向的な設計になりました。これにより、複数のタートルオブジェクトを生成し、それぞれを独立して制御することが容易になりました。
    • 従来の関数ベースの利用方法(from turtle import * のようにして関数を直接呼び出す)も引き続き可能ですが、より推奨されるのはimport turtleとして、turtle.Turtle()でタートルオブジェクトを作成し、そのオブジェクトのメソッドを呼び出す方法です。
  1. イベント駆動型プログラミングへの対応

    • 画面クリックやキーボード入力などのイベントを扱うための機能が強化されました。これにより、ユーザーインタラクションを伴うより複雑なグラフィックスアプリケーションを作成できるようになりました。
    • 例: screen.onclick(my_function)screen.onkey(another_function, "space") など。
  2. 豊富な描画機能と設定オプション

    • 線の色、太さ、塗りつぶし、図形の描画(円、点、多角形など)に関するより多くのメソッドが追加または改善されました。
    • タートルの形状(矢印、亀、円など)、表示・非表示の切り替え、アニメーション速度の制御など、描画に関する詳細な設定が可能になりました。
  3. モジュールの安定性とパフォーマンス

    • Python 2.6以降、turtleモジュールはTkinter GUI環境をベースにしており、その安定性とパフォーマンスが向上しました。
    • 複雑な描画でも比較的スムーズに動作するように、tracer()関数による描画更新の制御などが導入されました。
  4. Python 3との互換性

    • Python 2.6で導入されたturtleモジュールの機能の多くは、Python 3系でもそのまま引き継がれています。
    • ただし、Python 2とPython 3の間には基本的な言語構文の違い(例: print文からprint()関数への変更など)があるため、完全に同一のコードが動作するわけではありませんが、turtleモジュール自体のAPIは非常に似ています。


turtleモジュールは視覚的に分かりやすいプログラミングツールですが、いくつかの一般的な落とし穴があります。

Screen オブジェクトの欠落または誤用

  • 解決策:
    • Python 3系の場合:
      import turtle
      wn = turtle.Screen() # スクリーンオブジェクトの作成
      t = turtle.Turtle()  # タートルオブジェクトの作成
      
      # ここに描画コード
      
      wn.mainloop() # ウィンドウを開いたままにする(イベントループを開始)
      # または wn.exitonclick() # クリックで終了
      
    • wn.mainloop()wn.exitonclick() を記述しないと、スクリプトが終了すると同時にウィンドウも閉じてしまいます。
  • 原因: turtleグラフィックスは、描画が行われる「スクリーン(画面)」が必要です。スクリーンのセットアップと、描画後にスクリーンを開いたままにするための指示が不足している場合によく発生します。
  • エラーの状況: プログラムがすぐに終了してしまう、または描画ウィンドウが表示されない。

NameError (未定義の変数/関数)

  • 解決策:
    • オブジェクトを正しくインスタンス化する:
      import turtle
      # 推奨される方法
      screen = turtle.Screen()
      my_turtle = turtle.Turtle()
      my_turtle.forward(100)
      
      # 非推奨だが、一部の入門書で見られる方法 (NameErrorを避けるため)
      # from turtle import *
      # forward(100) # この場合、グローバルなタートルが使用される
      # mainloop()
      
    • オブジェクト名を一致させる(例: my_turtlet と書いてしまった場合)。
  • 原因: タートルオブジェクトやスクリーンオブジェクトを適切に作成していない、または誤った名前で参照しようとしている。from turtle import * を使っている場合は、turtle.Turtle() の代わりに Turtle() と書く必要があります。
  • エラーの状況: t.forward()screen.bgcolor() などのメソッドを呼び出す際に NameError: name 't' is not defined のようなエラーが表示される。

ウィンドウがすぐに閉じてしまう (Python 2.x からの移行者向け)

  • 解決策:
    • 前述の「1. Screen オブジェクトの欠落または誤用」と同様に、wn.mainloop()wn.exitonclick() を必ずコードの最後に記述してください。
  • 原因: Python 2.x時代の一部のコードでは、最後にraw_input()などを置いてプログラムの終了を待つような記述が見られましたが、Python 3のturtleではイベントループ(mainloop()exitonclick())を使うのが標準的です。
  • エラーの状況: turtleウィンドウがチラッと表示されてすぐに消えてしまう。

AttributeError (存在しないメソッドの呼び出し)

  • 解決策:
    • turtleモジュールのドキュメントを確認し、正しいメソッド名と引数を確認する。
    • エディタの自動補完機能を利用する。
  • 原因: オブジェクトが持っていない属性(メソッドやプロパティ)を呼び出そうとしている。
  • エラーの状況: my_turtle.forword(100) のように、メソッド名のスペルミスがある場合 (forward の代わりに forword)。

TurtleGraphicsError (無効な引数)

  • 解決策:
    • 受け入れられる引数の形式(例: 色は "red"(R, G, B) のタプル、角度は数値など)を確認する。
    • エラーメッセージにヒントが書かれていることが多いので、よく読む。
  • 原因: メソッドに渡された引数の値が、そのメソッドが受け付ける範囲や形式ではない。
  • エラーの状況: t.color("レッド") のように、色名や引数の値が無効な場合に発生することがあります。

モジュールのインポートに関する問題

  • 解決策:
    • 自分で作成したturtle.pyというファイルがある場合は、名前を変更するか削除する。
    • Pythonのインストールが破損している場合は、再インストールを検討する。
  • 原因: 通常、turtleはPythonの標準ライブラリの一部なので、このエラーは稀です。しかし、仮想環境の破損や、自分でturtle.pyという名前のファイルを作成してしまい、標準のturtleモジュールがインポートされなくなっている場合があります。
  • エラーの状況: ModuleNotFoundError: No module named 'turtle'

描画が遅い、または画面がちらつく

  • 解決策:
    • screen.tracer(0) を描画開始前に呼び出し、描画の自動更新をオフにする。
    • 全ての描画が完了した後に screen.update() を呼び出し、手動で一度だけ画面を更新する。
    • 例:
      import turtle
      wn = turtle.Screen()
      wn.tracer(0) # 自動更新をオフ
      
      t = turtle.Turtle()
      for _ in range(36):
          t.circle(100)
          t.right(10)
      
      wn.update() # 全ての描画後に一度更新
      wn.mainloop()
      
  • 原因: turtleはデフォルトで各描画コマンドのたびに画面を更新しようとします。
  • エラーの状況: 複雑な描画や大量のタートル操作を行うと、画面の更新が遅く、ちらつきが見られる。

Mac (macOS) 環境での問題

  • 解決策:
    • Pythonのバージョンを確認する: 公式サイトからダウンロードしたPythonディストリビューションを使用することが推奨されます。
    • pythonw コマンドで実行する: ターミナルから python your_script.py の代わりに pythonw your_script.py を試してみてください。pythonwはGUIアプリケーションを適切に起動するためのものです。
    • 仮想環境を適切に設定する: 仮想環境を使用している場合、Tkinterが正しくリンクされているか確認します。
    • Tkinterの再インストール/アップグレード: 必要に応じて、OSに組み込まれているTkinterまたはPythonと一緒にインストールされるTkinterを更新する。
  • 原因: macOSのTkinter(turtleが依存するGUIライブラリ)のバージョンや設定、またはPythonのインストール方法に起因する場合があります。特にHomebrewなどでPythonをインストールした場合に発生しやすいです。
  • エラーの状況: macOSでturtleを実行すると、ターミナルから起動してもPython Launcherから起動しても、ウィンドウが表示されない、またはクラッシュする。


基本的な描画とオブジェクト指向アプローチ

Python 2.6以降、特にPython 3では、turtle.Turtle()で個別のタートルオブジェクトを作成し、そのメソッドを呼び出すオブジェクト指向的なアプローチが推奨されます。

import turtle

# 1. スクリーンオブジェクトの作成
# 描画が行われるキャンバス(画面)を作成します。
# これがないと、描画ウィンドウはすぐに閉じてしまいます。
wn = turtle.Screen()
wn.title("初めてのタートルグラフィックス") # ウィンドウのタイトル設定
wn.bgcolor("lightblue") # 背景色設定

# 2. タートルオブジェクトの作成
# 画面上で描画を行う「タートル」を作成します。
alex = turtle.Turtle()
alex.color("red")     # タートルの色を設定
alex.pensize(3)       # ペンの太さを設定
alex.shape("turtle")  # タートルの形状を「亀」にする

# 3. 描画コマンド
alex.forward(100) # 100ピクセル前進
alex.left(90)     # 左に90度回転
alex.forward(100)
alex.left(90)
alex.forward(100)
alex.left(90)
alex.forward(100)

# 4. ウィンドウを閉じないようにする
# プログラムが終了するのを待ち、ユーザーがウィンドウを閉じるまで画面を開いたままにします。
# これがないと、描画された直後にウィンドウが消えてしまいます。
wn.mainloop()
# または wn.exitonclick() # クリックでウィンドウを閉じる

ポイント

  • wn.mainloop(): Tkinterイベントループを開始し、ウィンドウが開いたままになるようにします。
  • alex.method(): 作成したタートルオブジェクト(alex)のメソッドを呼び出して描画を制御します。
  • turtle.Turtle(): 描画を行うタートル(亀)のオブジェクトを作成します。
  • turtle.Screen(): 描画用のウィンドウ(スクリーン)を作成します。
  • import turtle: turtleモジュール全体をインポートします。

複数のタートルオブジェクトの制御

Python 2.6以降のオブジェクト指向の恩恵として、複数のタートルを独立して制御することができます。

import turtle

wn = turtle.Screen()
wn.setup(width=600, height=600) # ウィンドウサイズの設定
wn.bgcolor("lightgreen")

# タートル1の作成と設定
alice = turtle.Turtle()
alice.color("blue")
alice.pensize(2)
alice.shape("arrow")
alice.speed(5) # 描画速度 (1: slowest, 10: fast, 0: fastest)

# タートル2の作成と設定
bob = turtle.Turtle()
bob.color("purple")
bob.pensize(4)
bob.shape("circle")
bob.speed(3)

# アリスによる描画
alice.penup() # ペンを上げる(描画しない)
alice.goto(-100, 0) # 位置を移動
alice.pendown() # ペンを下げる(描画を開始)
for _ in range(4):
    alice.forward(200)
    alice.right(90)

# ボブによる描画
bob.penup()
bob.goto(100, 0)
bob.pendown()
for _ in range(3):
    bob.forward(150)
    bob.left(120)

wn.mainloop()

ポイント

  • alice.speed(): タートルの描画速度を制御します。
  • alice.goto(x, y): 指定した座標にタートルを移動させます。
  • alice.penup(), alice.pendown(): ペンを上げ下げして、線を描かずに移動したり、描画を開始したりできます。
  • wn.setup(): ウィンドウのサイズを具体的に指定できます。

イベント駆動型プログラミング

Python 2.6以降では、キー入力やマウスクリックといったイベントを処理するための機能が強化されました。

import turtle

wn = turtle.Screen()
wn.title("イベントハンドリングの例")
wn.bgcolor("yellow")
wn.setup(width=600, height=400)

player = turtle.Turtle()
player.color("orange")
player.shape("triangle")
player.penup() # 移動時に線を描かない

# キー入力イベントのハンドラ関数
def move_left():
    x = player.xcor() # 現在のX座標を取得
    player.setx(x - 20) # X座標を20減らす

def move_right():
    x = player.xcor()
    player.setx(x + 20)

def change_color():
    player.color("blue") # 色を変更

# クリックイベントのハンドラ関数
def screen_click(x, y):
    player.goto(x, y) # クリックした座標に移動

# イベントリスナーのセットアップ
wn.listen() # キーボード入力を受け付けるようにする
wn.onkey(move_left, "Left") # 左矢印キーが押されたらmove_leftを呼び出す
wn.onkey(move_right, "Right") # 右矢印キーが押されたらmove_rightを呼び出す
wn.onkey(change_color, "c") # 'c'キーが押されたらchange_colorを呼び出す

wn.onclick(screen_click) # 画面がクリックされたらscreen_clickを呼び出す

wn.mainloop()

ポイント

  • player.xcor(), player.setx(): タートルの現在のX座標を取得したり、設定したりするメソッドです。
  • wn.onclick(handler): 画面がクリックされたときにhandler関数を呼び出します。handler関数はクリックされたX, Y座標を引数として受け取ります。
  • wn.onkey(handler, key_string): 指定されたキーが押されたときにhandler関数を呼び出します。
  • wn.listen(): スクリーンがキーボードイベントを「聞く」ように設定します。

アニメーションの制御

Python 2.6以降では、tracer()update()を使って、よりスムーズなアニメーションを作成できます。これにより、複雑な描画でもちらつきを抑えられます。

import turtle

wn = turtle.Screen()
wn.title("スムーズなアニメーション")
wn.bgcolor("black")
wn.setup(width=700, height=700)

# 自動更新をオフにする
# これにより、個々の描画ステップが表示されなくなり、
# 最後の結果だけが一気に表示されるようになります。
wn.tracer(0)

pen = turtle.Turtle()
pen.color("cyan")
pen.pensize(2)
pen.speed(0) # 最速に設定(tracer(0)と併用すると良い)

# 複雑な図形を描く例(フラクタル図形など)
def draw_fractal(t, order, size):
    if order == 0:
        t.forward(size)
    else:
        draw_fractal(t, order - 1, size / 3)
        t.left(60)
        draw_fractal(t, order - 1, size / 3)
        t.right(120)
        draw_fractal(t, order - 1, size / 3)
        t.left(60)
        draw_fractal(t, order - 1, size / 3)

pen.penup()
pen.goto(-200, 0)
pen.pendown()

draw_fractal(pen, 4, 400) # コッホ曲線のような図形を描く

# 描画が完了したら、手動で画面を更新する
wn.update()

wn.mainloop()
  • pen.speed(0): これも最速設定ですが、tracer(0)を使用する場合は、描画速度の体感には影響しません(すべての描画がupdate()で一気に表示されるため)。
  • wn.update(): tracer(0)が設定されている場合、このメソッドを呼び出すことで、保留中の描画コマンドが一度に画面に表示されます。複雑な描画を行う際に非常に有用です。
  • wn.tracer(0): 画面の自動更新を無効にします。これにより、描画処理が非常に速くなり、ちらつきがなくなります。


turtleモジュールは、主に教育目的やシンプルな図形描画のために設計されています。しかし、より複雑なインタラクティブなアプリケーション、ゲーム、データ可視化、または高度なGUIを構築したい場合、以下のような代替ライブラリを検討する価値があります。

Tkinter (標準ライブラリ)

  • コード例(簡単なGUIと描画):
    import tkinter as tk
    
    def draw_square(canvas, x, y, size, color):
        canvas.create_rectangle(x, y, x + size, y + size, fill=color, outline="black")
    
    def button_click():
        print("ボタンがクリックされました!")
        # 例えば、ここで描画を変更したりできる
        canvas.create_oval(50, 50, 150, 150, fill="blue")
    
    root = tk.Tk()
    root.title("Tkinter GUIと描画")
    
    # 描画領域 (Canvas) の作成
    canvas = tk.Canvas(root, width=400, height=300, bg="white")
    canvas.pack(pady=10)
    
    # 描画の例
    draw_square(canvas, 100, 100, 50, "red")
    canvas.create_line(0, 0, 400, 300, fill="green", width=2)
    
    # ボタンの作成
    button = tk.Button(root, text="描画変更", command=button_click)
    button.pack(pady=5)
    
    root.mainloop()
    
  • 欠点:
    • モダンなUIデザインの要求には応えにくい(見た目が古く感じる場合がある)。
    • 大規模なアプリケーション開発には向かない。
  • 利点:
    • Pythonの標準ライブラリなので、追加インストールが不要。
    • 比較的軽量で、学習コストも高すぎない。
    • 基本的なGUIアプリケーションのプロトタイプ作成に便利。
  • turtleとの関連: turtleモジュールのScreenオブジェクトはTkinterのCanvasウィジェット上に描画されます。そのため、Tkinterを直接使用することで、turtleではできないような詳細なGUI要素(ボタン、テキスト入力欄、メニューなど)と描画を組み合わせることができます。

Pygame (ゲーム開発)

  • コード例(簡単なアニメーション):
    import pygame
    
    # Pygameの初期化
    pygame.init()
    
    # スクリーン設定
    screen_width = 800
    screen_height = 600
    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption("Pygame アニメーション")
    
    # 色の定義
    WHITE = (255, 255, 255)
    RED = (255, 0, 0)
    
    # 円の初期位置と速度
    circle_x = 100
    circle_y = 100
    circle_radius = 20
    speed_x = 5
    speed_y = 5
    
    running = True
    clock = pygame.time.Clock() # フレームレート制御用
    
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
    
        # 円の移動
        circle_x += speed_x
        circle_y += speed_y
    
        # 壁との衝突判定
        if circle_x + circle_radius > screen_width or circle_x - circle_radius < 0:
            speed_x *= -1
        if circle_y + circle_radius > screen_height or circle_y - circle_radius < 0:
            speed_y *= -1
    
        # 画面を白で塗りつぶす
        screen.fill(WHITE)
    
        # 円を描画
        pygame.draw.circle(screen, RED, (int(circle_x), int(circle_y)), circle_radius)
    
        # 画面を更新
        pygame.display.flip()
    
        # フレームレート制御
        clock.tick(60) # 60 FPS
    
    pygame.quit()
    
  • 欠点:
    • GUIアプリケーション開発には不向き(ゲーム以外の一般的なアプリケーションには向かない)。
    • Tkinterよりは学習コストが高い。
  • 利点:
    • 2Dゲーム開発に非常に強力。
    • 高速なグラフィックス描画が可能。
    • ゲームループ、イベント処理、衝突判定など、ゲームに必要な機能が充実。
  • turtleとの関連: turtleが描画を「線」として捉えるのに対し、Pygameは「ピクセル」や「サーフェス(画像)」として直接扱います。より高速で複雑なアニメーションや、多数のスプライト(キャラクターやオブジェクト)を扱うのに適しています。

PyQt / PySide (高度なGUI開発)

  • コード例(簡単なウィンドウとボタン):
    import sys
    from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QLabel
    from PyQt5.QtGui import QPainter, QPen, QBrush, QColor
    from PyQt5.QtCore import Qt
    
    class DrawingWidget(QWidget):
        def __init__(self):
            super().__init__()
            self.drawing_data = [] # 描画する図形のリスト
    
        def paintEvent(self, event):
            painter = QPainter(self)
            painter.setRenderHint(QPainter.Antialiasing) # アンチエイリアシング
    
            # 既存の図形を描画
            for shape_type, *args in self.drawing_data:
                if shape_type == "circle":
                    x, y, radius, color = args
                    painter.setPen(QPen(QColor(color), 2))
                    painter.setBrush(QBrush(QColor(color)))
                    painter.drawEllipse(x - radius, y - radius, radius * 2, radius * 2)
                elif shape_type == "rect":
                    x, y, w, h, color = args
                    painter.setPen(QPen(QColor(color), 2))
                    painter.setBrush(QBrush(QColor(color)))
                    painter.drawRect(x, y, w, h)
    
        def add_circle(self, x, y, radius, color):
            self.drawing_data.append(("circle", x, y, radius, color))
            self.update() # 描画を更新
    
        def add_rectangle(self, x, y, w, h, color):
            self.drawing_data.append(("rect", x, y, w, h, color))
            self.update() # 描画を更新
    
    class MainWindow(QWidget):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("PyQt GUIとカスタム描画")
            self.setGeometry(100, 100, 600, 400)
    
            main_layout = QVBoxLayout()
    
            self.drawing_widget = DrawingWidget()
            main_layout.addWidget(self.drawing_widget)
    
            button_circle = QPushButton("円を追加")
            button_circle.clicked.connect(self.add_a_circle)
            main_layout.addWidget(button_circle)
    
            button_rect = QPushButton("四角を追加")
            button_rect.clicked.connect(self.add_a_rectangle)
            main_layout.addWidget(button_rect)
    
            self.setLayout(main_layout)
    
        def add_a_circle(self):
            self.drawing_widget.add_circle(150, 150, 40, "green")
    
        def add_a_rectangle(self):
            self.drawing_widget.add_rectangle(300, 100, 80, 60, "purple")
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        main_window = MainWindow()
        main_window.show()
        sys.exit(app.exec_())
    
  • 欠点:
    • 学習コストが非常に高い。
    • ライセンスの考慮が必要な場合がある(PyQtはGPL/商用、PySideはLGPL)。
    • アプリケーションのサイズが大きくなる傾向がある。
  • 利点:
    • 非常に強力で柔軟なGUIアプリケーションを開発できる。
    • 見た目がモダンで、カスタマイズ性が高い。
    • 大規模なデスクトップアプリケーション開発に適している。
    • Qt DesignerなどのGUIビルダツールと連携できる。
  • turtleとの関連: turtleとはレベルが全く異なります。Qtはウィジェット、レイアウト、イベントシステム、グラフィックスビューなど、GUI開発に必要なあらゆる要素を高度に抽象化して提供します。

Kivy (マルチタッチ/クロスプラットフォーム)

  • 欠点:
    • TkinterやPyQtに比べて学習リソースが少ない場合がある。
    • 軽量なデスクトップアプリにはややオーバーキル。
  • 利点:
    • 美しいUIを構築できる。
    • マルチタッチ入力にネイティブ対応。
    • クロスプラットフォーム展開が容易。
    • 独自の「KV言語」でUIの記述が可能。
  • turtleとの関連: turtleとは全く異なる設計思想で、主にモバイルやタッチインターフェースを持つデバイス向けに、現代的なUI/UXを構築するのに適しています。

Matplotlib (データ可視化)

  • 欠点:
    • 一般的なGUIアプリケーションやゲーム開発には向かない。
    • リアルタイムな描画処理には不向きな場合がある。
  • 利点:
    • 豊富なグラフの種類(線グラフ、散布図、棒グラフ、ヒストグラムなど)。
    • 高いカスタマイズ性。
    • Jupyter Notebookなどとの連携が容易。
    • 科学計算ライブラリ(NumPy, SciPy)との親和性が高い。
  • turtleとの関連: turtleがプログラミング学習のための抽象化された描画ツールであるのに対し、Matplotlibはデータや関数を視覚的に表現するための専門ツールです。