nikkie-ftnextの日記

イベントレポートや読書メモを発信

あれ? Pythonでimportしただけなのに、SyntaxError?

またオレ何かやっちゃいました?

目次

用語確認:importしただけなのに、SyntaxError

組み込み例外のドキュメントより
https://docs.python.org/ja/3/library/exceptions.html#SyntaxError

SyntaxErrorは

パーザが構文エラーに遭遇した場合に送出されます。
この例外は import 文、 () で (対話的な実行時にも) 起こる可能性があります。

import文はこちら
https://docs.python.org/ja/3/reference/simple_stmts.html#import

事件現場

素晴らしいスクリプトを書きました、async.py

def awesome() -> None:
    print("Awesome ✨")

importしてみます。

% python3.12  # Python 3.12.6
>>> import async
  File "<stdin>", line 1
    import async
           ^^^^^
SyntaxError: invalid syntax

スクリプトとしては実行できます

% python3.12 -i async.py
>>> awesome()
Awesome ✨

Python 3.7以降でasync予約語

「SyntaxError: invalid syntax」は、async予約語だからです。

Python 3.7から予約語です。
https://docs.python.org/ja/3/whatsnew/3.7.html#summary-release-highlights

async と await は予約されたキーワードになりました。

https://docs.python.org/ja/3/whatsnew/3.7.html#changes-in-python-behavior

async and await names are now reserved keywords. Code using these names as identifiers will now raise a SyntaxError.

予約語のドキュメント
https://docs.python.org/ja/3/reference/lexical_analysis.html#keywords

以下の識別子は、予約語、または Python 言語における キーワード (keyword) として使われ、通常の識別子として使うことはできません。

importはimport <通常の識別子>となるため、通常の識別子に予約語asyncが来られず、SyntaxErrorという理解です。
同じ理由で、関数名にも使えませんね。

>>> def async():
  File "<stdin>", line 1
    def async():
        ^^^^^
SyntaxError: invalid syntax

Python 3.7より前は予約語ではないのでimportできます。

% docker run --rm -it --platform linux/x86_64 -v $PWD/async.py:/work/async.py -w /work python:3.6 python
>>> import async
>>> async.awesome()
Awesome ✨
% docker run --rm -it --platform linux/x86_64 -v $PWD/async.py:/work/async.py -w /work python:3.7 python
>>> import async
  File "<stdin>", line 1
    import async
               ^
SyntaxError: invalid syntax

async予約語OSSに見つけた事象

知っている中から2つ紹介

(1) Celery

from . import async, baseasync.pyのimport)でSyntaxErrorが送出されています。
asynchronous.pyにrenameして修正しています。

(2) Sphinx

私が報告していました。
関数の引数にasyncが使われていて、SyntaxErrorが送出されました

終わりに

importしただけなのにSyntaxError、予約語をimportしていたためでした。
予約語は関数名や仮引数に使ってもSyntaxErrorです。

学び:予約語は、通常の識別子として使えません。

P.S. 構造的パターンマッチとソフトキーワード

Python 3.10で追加された「構造的パターンマッチ」
https://docs.python.org/ja/3/whatsnew/3.10.html#pep-634-structural-pattern-matching

こちらに使うmatchcaseですが、予約語ではなく、ソフトキーワードとして導入されています。
https://docs.python.org/ja/3/reference/lexical_analysis.html#soft-keywords

Some identifiers are only reserved under specific contexts. These are known as soft keywords.

As soft keywords, their use in the grammar is possible while still preserving compatibility with existing code that uses these names as identifier names.

asyncと同様キーワードとして追加すると影響は大きかったと思います(re.match()などにも影響)。
ソフトキーワードという意思決定の背景が少しだけ分かった気がします。