Python の奇妙なこと: 目に見えない文字!

序文

  今日は非常に奇妙なことを共有したいと思います。コードを書いているときに目に見えない文字に遭遇しました。

1. 起因

pipreqs今日、プロジェクトをエクスポートするために依存していたライブラリを  使用しているときに、突然エラーが発生しました。

pipreqs . --encoding=utf-8 --force

# 以下是报错信息
ERROR: Failed on file: ./build.py
Traceback (most recent call last):
  File "/usr/local/bin/pipreqs", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.8/dist-packages/pipreqs/pipreqs.py", line 528, in main
    init(args)
  File "/usr/local/lib/python3.8/dist-packages/pipreqs/pipreqs.py", line 455, in init
    candidates = get_all_imports(input_path,
  File "/usr/local/lib/python3.8/dist-packages/pipreqs/pipreqs.py", line 131, in get_all_imports
    raise exc
  File "/usr/local/lib/python3.8/dist-packages/pipreqs/pipreqs.py", line 117, in get_all_imports
    tree = ast.parse(contents)
  File "/usr/lib/python3.8/ast.py", line 47, in parse
    return compile(source, filename, mode, flags,
  File "<unknown>", line 1
    # -*- coding:utf-8 -*-
    ^
SyntaxError: invalid character in identifier

  直接問い合わせてみるとSyntaxError#無効な文字だったことが判明し、#非常に無実であることを意味する文字であり、関係者は非常にショックを受けていました。これは世界を離れる素晴らしい兆候であり、世界に滑り込むという素晴らしい冗談ではありませんか?? ? これはたった 1 行のコード コメントですが、これが間違っているはずがありません。

ここに画像の説明を挿入します

2. 調査

  初めてこの種の邪悪な現象に遭遇したとき、pipreqsソースコードを確認したところ、非常に単純なコードだったので、エラーが報告された部分を抜粋してみました。

# pipreqs/pipreqs.py line 112
for file_name in files:
    file_name = os.path.join(root, file_name)
    with open(file_name, "r", encoding=encoding) as f:
        contents = f.read()
    try:
        tree = ast.parse(contents)	# 在这里报错了
        for node in ast.walk(tree):
            if isinstance(node, ast.Import):
                for subnode in node.names:
                    raw_imports.add(subnode.name)
            elif isinstance(node, ast.ImportFrom):
                raw_imports.add(node.module)
    except Exception as exc:
    	...

  意味も分かりやすく、pipreqs現在のプロジェクト配下のpythonファイルを全て読み込み、astライブラリを使って構文解析を行い、pythonそのファイルが依存しているライブラリ名を取得します。この部分がエラーを報告していたので、直接取り出したのですが、この時点でast何か重大な問題があるのではないかと疑いましたbug

3. 高エネルギー

astファイルの解析にバグがあること  を確認するために、python現在のプロジェクト内のすべてのファイルを 1 つずつテストしましたが、予想を上回る展開となり、2 番目のファイルは(process_data.py)解析できました。
  このファイルを見てみると、冒頭に同じコメントがありましたが、エラーは報告されていませんでした。エンコードに問題があるのでしょうか?開けてPycharm見てみましたが、特に問題はありませんでした。

ここに画像の説明を挿入します
  これはあまりにも奇妙だったので、debugもう一度チェックしてファイルの内容を調べて、何も問題がないことを確認しました。

ここに画像の説明を挿入します
  理解できなかったので、次のように質問しましたChatGPT

ここに画像の説明を挿入します
  疑問点は 4 つあり、基本的には 1 つずつ解消していきましたが、python 3.8ファイルはutf-8暗号化されており、文法的な誤りはなく、コメントにも問題はありませんでした。しかし、理解できないことが 1 つあります。それは、非表示の特殊文字ですか?
  見えない?キャラクターなので、目に見えなくても場所があるはずです。その後、最も奇妙なことが起こりました。

ここに画像の説明を挿入します
  これは、実際には最初の位置に null 文字があります。空の文字でもスペースを占有することはできますか?
  を印刷してみるとASCII、値は となっており65279、空文字にも実はASCII値が入っていたのですが、ふと、この問題は単純ではないのではないかと感じたのですが、本当に目に見えないのでしょうか?

ここに画像の説明を挿入します

4. 混乱を解消する

  Baidu が調べたところ、ASCIIこの値は65279ファイルで使用されているエンコーディングによって引き起こされていることがわかりましたUTF-8 BOM。これは、環境内でファイルを作成するときのデフォルトのエンコーディング方法ですWindows。また、これを具体的に調べたところ、実際には次のとおりであることがわかりました。

ここに画像の説明を挿入します
  にもこの設定がありますPycharm。デフォルトでは、Pycharmで新しいファイルを作成するときにエンコーディングが使用されます。UTF-8 with NO BOMこれはよく言われることですUTF-8。一部のライブラリがファイルを正常に解析でき、一部のライブラリが解析できない理由は、一部のファイルがCreated inastにない可能性があるためです。Pycharmこの奇妙な時間の出来事に。同時に、バイナリ モードでファイルを読み取ったところ、最初の 3 バイトが であることがわかりました\xEF\xBB\xBF。これらはUTF-8 BOMエンコード中に自動的に追加されました。

py_file = './build.py'
with open(py_file, 'r', encoding='utf-8') as f:
    contents = f.read()
    if ord(contents[0]) == 65279:
        print('UTF-8 BOM')

with open(py_file, 'rb') as f:
    contents = f.read(3)
    if contents == b'\xEF\xBB\xBF':
        print('UTF-8 BOM')

# UTF-8 BOM
# UTF-8 BOM

  そこで、ファイルエンコーディングを から にUTF-8 BOM変更したところUTF-8、問題は解決しました。

ここに画像の説明を挿入します


  WeChat 公開アカウントをフォローして、夏小悠より多くの記事、論文PPT、その他の情報を入手してください ^_^

おすすめ

転載: blog.csdn.net/qq_42730750/article/details/132249961