Python 3.14新機能:PyREPL(対話型シェル)に追加された構文ハイライト機能とそのカスタマイズPython最新情報キャッチアップ

Python 3.14ではPyREPLやモジュールのヘルプなどで、構文がハイライト表示されるようになりました。その概要とカスタマイズの方法について見てみましょう。

» 2025年10月31日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「Python最新情報キャッチアップ」のインデックス

連載目次

 「What's new in Python 3.14」によれば、Pythonの対話型シェル(PyREPL)に構文ハイライト機能が付加されている。PyREPLを起動すれば一目瞭然のことだが、今回はこれについて簡単に触れるとともに、そのカスタマイズについても紹介する。

構文ハイライト機能

 pythonコマンドを引数なしで実行すると対話的にコマンドを実行するためのPyREPLが起動される。Python 3.14ではこのPyREPLに構文ハイライト機能が追加された。以下は実際に構文ハイライトが機能しているところだ。

構文ハイライト機能が有効なのでキーワードやコメントが色付きで表示されている 構文ハイライト機能が有効なのでキーワードやコメントが色付きで表示されている

 なお、構文ハイライト機能は環境変数「PYTHON_BASIC_REPL」「NO_COLOR」などを1に設定すると無効化される(詳細はPythonのドキュメント「色の制御」を参照されたい)。PYTHON_BASIC_REPLを1にするとPythonベースのREPLが起動され、Python 3.14で追加された[Tab]キーによる入力補完機能なども無効化される点には注意しよう。


かわさき

 どうもHPかわさきです。

 今も書きましたが、Python 3.14ではPyREPLに入力補完機能も追加されています。例えば「from concurrent import in」に続けて[Tab]キーを押せば、concurrentモジュールで定義されていて「in」で始まるサブモジュールが候補として表示されます。ただし、Python 3.14の時点では、モジュールの属性については補間の候補として表示されません。例えば、「from concurrent.interpreters import cr」に続けて[Tab]キーを押してもcreate関数が候補として表示されないということです。Pythonのバージョンが上がるとともに、こうした機能がさらに向上することを願いましょう。


 デフォルトのテーマはコントラストを意識したもので、かつ4ビットのANSIカラーコードを使うようになっている。このため、上の画像にもあったようにコメントが赤い文字で表示されるなど、普段使用しているエディタの構文ハイライトとは異なることにギョッとする方もいるだろう。そこで、以下では構文ハイライトをカスタマイズする方法を紹介する。

構文ハイライトをカスタマイズするには

 PyREPLの構文ハイライトをカスタマイズするには_colorizeモジュールを使用する。


かわさき

 以下は_colorizeのソースコードを基に、筆者が「こうしたらうまくいった」というお話です。「What's new in Python 3.14」にもあるように以下で取り上げるカスタマイズ方法は将来的に変更される可能性もあることに留意してください。


 _colorizeモジュールには以下のような関数やクラスが定義されている(一部抜粋)。

  • can_colorize関数:構文ハイライト可能であればTrueを、そうでなければFalseを返す
  • set_theme関数:構文ハイライトのテーマを設定する
  • get_theme関数:現在の構文ハイライトのテーマを取得する
  • ANSIColorsクラス:構文ハイライトに指定するANSIカラーを保持する
  • Themeクラス:構文ハイライトの全体を表すクラス
  • Syntaxクラス:構文ハイライトのうち、PyREPLの構文要素を表すクラス
  • ThemeSectionクラス:構文ハイライトのテーマを表すクラス
  • default_theme属性:現在のテーマを表すThemeオブジェクト

 構文ハイライトは幾つかのテーマセレクション(ThemeSection)で構成される。例えば、PyREPL環境で構文ハイライトを付加するsyntaxセクション(Syntaxクラスが対応)やargparseセクション(ArgParseクラスが対応)などがそうである。これをひとまとめにしたものがThemeクラスとなる。

 デフォルトのテーマは_colorize.default_themeオブジェクトとして参照できる。また、現在の設定は_colorize.get_theme関数で取得できる。

import _colorize

print(_colorize.default_theme)

現在のテーマを取得

 これを実行すると、次のようになる。

現在のテーマ 現在のテーマ

 出力をよく見ると、Themeの中にargparseやsyntax、tracebackなどの語があるのが分かる。これらがいわゆるテーマセクションである。そして、個々のテーマセクションにはそれを構成する要素が含まれている。syntaxセクションについて見てみよう。

syntax_section = _colorize.default_theme.syntax

print(syntax_section)

syntaxセクションの現在の設定

 まず重要なのはセクションにはThemeオブジェクトの属性としてドット記法でアクセスできるということだ。上のコードでは「_colorize.default_theme.syntax」として現在のsyntaxセクションの設定を取得して、それを出力している。実行結果は次のようになる。

syntaxセクションの現在の設定 syntaxセクションの現在の設定

 「prompt」「keyword」「comment」など、どんなところの色を示すのかが想像できる語が並んでいるのが分かるはずだ。そして、それらの値は色を設定するためのエスケープシーケンスとなっている(ANSIカラー)。これらの色をエスケープシーケンスのまま扱うのが面倒くさいので、ANSIColorsオブジェクトがある。これを使うことで、「_colorize.ANSIColors.GREEN」のように属性として各色にアクセスできる(その値がエスケープシーケンスとなる)。

 テーマをカスタマイズするには、今見てきたオブジェクトを使用することになるが、その方法は幾つかある。

  1. _colorize.default_themeオブジェクトのcopy_withメソッドを使って、特定の箇所をカスタマイズしたThemeオブジェクトを作成し、それをset_theme関数に渡す
  2. _colorize.default_themeオブジェクトにある特定のセクションのcopy_withメソッドを使って、特定の箇所をカスタマイズしたThemeSection(のサブクラスの)オブジェクトを作成し、そこからThemeオブジェクトを作成してset_theme関数に渡す
  3. スクラッチでセクションオブジェクトやThemeオブジェクトを作成して、それをset_theme関数に渡す

Themeオブジェクトのcopy_withメソッドを使う

 簡単そうに見えるのは最初の方法なので、これを紹介する。また以下ではsyntaxセクションを例とする。

from _colorize import default_theme, set_theme, Syntax, ANSIColors

comment_org = default_theme.syntax.comment  # コメントの色を保存
string_org = default_theme.syntax.string  # 文字列の色の保存

s = 'string is displayed in green'  # 色を確認するためだけの文字列

GREEN = ANSIColors.GREEN
RED = ANSIColors.RED

new_theme = default_theme.copy_with(
    syntax=Syntax(comment=GREEN, string=RED))
set_theme(new_theme)

最初の方法で配色をカスタマイズ

 ここでは_colorizeモジュールから幾つかの属性をインポートしておく。また、コメントと文字列の以前の色も保存しておこう。「s = 'string is displayed in green'」という行は文字列の色が緑であることを確認するためだけの行だ。GREENとREDは上で述べた_colorize.ANSIColorsで定義されている緑と赤のエスケープシーケンスである。


かわさき

 元の配色を保存したはいいけれど、次の例ではPythonを再起動することにしたので使わずじまいとなりました(笑)。


 default_themeオブジェクトのcopy_withメソッドには、カスタマイズしたい要素とその配色を指定する。ここではsyntaxセクションのcomment要素を緑に、string要素の色を赤に変更するような指定をしている。copy_withメソッドはThemeオブジェクトを返すので、それをset_theme関数に渡せばカスタマイズが完了する。

 実行結果を以下に示す。

カスタマイズにより文字列の色が赤に、コメントの色が緑に変わった カスタマイズにより文字列の色が赤に、コメントの色が緑に変わった

 配色が変更されていることを確認してほしい。

Syntaxオブジェクトのcopy_withメソッドを使う

 次にセクションオブジェクトのcopy_withメソッドを使う方法を見る。ここでもsyntaxセクションを例とする。基本的には上と同様だが、最初にSyntaxオブジェクトを作成してから、それを基にThemeオブジェクトを作成し、set_theme関数に渡すという手順を踏む。

from _colorize import default_theme, set_theme, Theme, Syntax, ANSIColors

s = 'string is displayed in green'  # 色を確認するためだけの文字列

GREEN = ANSIColors.GREEN
RED = ANSIColors.RED

new_syntax = default_theme.syntax.copy_with(
    **{'comment': GREEN, 'string': RED})
new_theme = Theme(syntax=new_syntax)
set_theme(new_theme)

セクションオブジェクト(Syntaxオブジェクト)、Themeオブジェクトを順番に作成

 ここでは「default_theme.syntax.copy_with(……)」としてSyntaxオブジェクトを作成してから、「Theme(syntax=……)」としてThemeオブジェクトの作成時にそのSyntaxオブジェクトを渡すようにした。その結果をset_theme関数に渡せばよい。実行結果は上と同様なので省略する。キーワード引数の代わりに辞書を展開したものを渡してもよい点には注目しておこう。

copy_withメソッドを使わずにスクラッチでThemeオブジェクトを作成する

 最後の方法はcopy_withメソッドを使わないパターンだ。

from _colorize import default_theme, set_theme, Theme, Syntax, ANSIColors

s = 'string is displayed in green'  # 色を確認するためだけの文字列

GREEN = ANSIColors.GREEN
RED = ANSIColors.RED

new_syntax = Syntax(**{'comment': GREEN, 'string': RED})
new_theme = Theme(syntax=new_syntax)
set_theme(new_theme)

スクラッチでSyntaxオブジェクトとThemeオブジェクトを作成する

 ここでは設定を変更したい要素だけをSyntaxオブジェクトの作成時に指定して、出来上がったSyntaxオブジェクトからThemeオブジェクトを作成している。結果は上と同じなので省略する。


かわさき

 あれ? 一番シンプルに書けた気がする(笑)。ただし、未指定の要素についてデフォルト値が採用されるのか、それまでに設定された値が生かされるのかについては未確認です。この後で紹介するset_syntax_theme関数で行っているように、現在の設定を辞書などに取得した上で必要な変更を行うのが安全でしょう。


 最後にSyntaxオブジェクトの設定を簡単に変更するための関数を紹介しておこう。これは「set_syntax_theme(comment='GREEN')」のように呼び出して使うことを想定したものだ。

import _colorize

def set_syntax_theme(**kwargs):
    # ANSIColorsオブジェクトが辞書的に使えないためカラーテーブルを作成
    color_table = {k: v for k, v in _colorize.ANSIColors.__dict__.items()
                   if not k.startswith('__')}

    # 現在のテーマから構文関係の要素を取得
    syntax_item = {k: v for k, v in _colorize.get_theme().syntax.items()}

    # 引数に従って、構文関係の要素の色を指定
    for k, v in kwargs.items():
        if k not in syntax_item:
            raise KeyError(f'{k} not exists')
        syntax_item[k] = color_table[v]

    # 指定を反映したSyntaxオブジェクトとThemeオブジェクトを作成
    mysyntax = _colorize.Syntax(**syntax_item)
    mytheme = _colorize.Theme(syntax=mysyntax)

    # テーマを設定
    _colorize.set_theme(mytheme)

mycolors = {'comment': 'GREEN', 'string': 'RED'}
set_syntax_theme(**mycolors)

構文ハイライトの要素の配色を変更するset_syntax_theme関数

 最初にやっているのは、_colorize.ANSIColorsを基にしたカラーテーブルの作成だ。これは「ANSIColors['GREEN']」のようにアクセスできなかったからだ。次に_colorize.get_theme関数で取得したThemeオブジェクトのsyntax属性から現在のsyntaxセクションの配色を辞書syntax_itemにまとめている。for文では渡されたキーワード引数が正しいかどうかを調べて正しければ、syntax_itemの値を変更している。最後にその辞書を使ってSyntaxオブジェクトを、さらにThemeオブジェクトを作成して、その結果をset_theme関数に渡している。

 実行例を以下に示す。

実行結果 実行結果

 おまけとして、現在のsyntaxセクションの設定を辞書にまとめるコードも示しておく(説明は省略)。

import _colorize

def dump_syntax_theme():
    color_table = {v: k for k, v in _colorize.ANSIColors.__dict__.items()
                   if not k.startswith('__')}
    syntax_items = {k: v for k, v in _colorize.get_theme().syntax.items()}
    result = {k: color_table[v] for k, v in syntax_items.items()}
    return result

現在のsyntaxセクションの設定を辞書にまとめるdump_syntax_theme関数

 なお、構文ハイライトのカスタマイズをPython起動時から有効にするには環境変数PYTHONSTARTUPにそのためのコードを記述したスクリプトファイルを指定すればよい。例えば、上のコードを少しだけ改変してみよう。

import _colorize

def set_syntax_theme(**kwargs):
    color_table = {k: v for k, v in _colorize.ANSIColors.__dict__.items()
                   if not k.startswith('__')}
    syntax_item = {k: v for k, v in _colorize.get_theme().syntax.items()}

    for k, v in kwargs.items():
        if k not in syntax_item:
            raise KeyError(f'{k} not exists')
        syntax_item[k] = color_table[v]

    mysyntax = _colorize.Syntax(**syntax_item)
    mytheme = _colorize.Theme(syntax=mysyntax)
    _colorize.set_theme(mytheme)

if __name__ == '__main__':
    mycolors = {'comment': 'GREEN', 'string': 'RED'}
    set_syntax_theme(**mycolors)

customize_color.pyファイル

 そして、環境変数PYTHONSTARTUPの値をcustomize_color.pyに設定する。これにより、次にPyREPLを起動したときには自動的にテーマのカスタマイズが行われる。

PyREPL起動時に自動的にテーマがカスタマイズされる PyREPL起動時に自動的にテーマがカスタマイズされる


かわさき

 取りあえず、Pythonの構文ハイライトをどうすればカスタマイズできるか、Python 3.14の時点での方法はこんな感じだと思います。ちゃんとドキュメント化されていないということは、これから大きく変わる可能性も高いと思いますが、興味のある方はどんどんカスタマイズしてみましょう。


「Python最新情報キャッチアップ」のインデックス

Python最新情報キャッチアップ

Copyright© Digital Advantage Corp. All Rights Reserved.

アイティメディアからのお知らせ

スポンサーからのお知らせPR

注目のテーマ

4AI by @IT - AIを作り、動かし、守り、生かす
Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。