Python で文頭に記載する文字コードの「アレ」（なんちゃら UTF-8 みたいなやつ）の名称と仕様

> [`shebang`（シバン）](https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%90%E3%83%B3_(Unix)) ではない。Python に限ったものではないので、それはわかる。
>
> 知りたいのは Python の教科書などで「ソースの文頭に書け」と言われる、**冒頭に記述する `utf-8` とかの文字コードのアレ**。

```python:これ↓（この名称と書き方を忘れる。てか知らない）
# -*- coding: <encoding name> -*-

#使用例: # -*- coding: utf_8 -*-
```

```python:たまにこれ↓（-*-はいずこ？）
# coding: <encoding name>

#使用例: # coding: utf_8
```
```python:たまにアレがないことも...
#
```

「[python 文頭に記載する アレ](https://www.google.co.jp/search?q=site:qiita.com+python+文頭に記載する+アレ)」とか「[python 文頭 記述 文字コード アレ](https://www.google.com/search?q=site:qiita.com+python+%E6%96%87%E9%A0%AD+%E8%A8%98%E8%BF%B0+%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89+%E3%82%A2%E3%83%AC)」の Qiita 記事をググっても出てこなかったので、自分のググラビリティ（備忘録）として。

## TL; DR <sub><sup>（今北産業）</sup></sub>

1. アレは英語で `Magic comment` と言います。
2. Python 3 の場合、ソースが UTF-8 の時は記載は不要（むしろ非推奨）です。
3. Python 3 で使える<ruby>コーデック<rt>文字コードのエンコード</rt></ruby>一覧はこちらになります。
    - [Standard Encodings](https://docs.python.org/3/library/codecs.html#standard-encodings) | Codecs | Library | v3 @ docs.python.org

## TS; DR <sub><sup>Python3 ソースコードの文字コード指定を完全に理解するコマケーこと</sup></sub>

### 取りまとめ

- 英語で `Magic comment` と言います

    <details><summary>Magic comment の日本語表記について</summary><div><br>
    
    英語の文献（<a href="https://www.python.org/dev/peps/pep-0263/#defining-the-encoding">PEP-263</a>）には「<code>magic comment</code>」という記載がありました。
    
    <blockquote>
    <p>To define a source code encoding, a <font color="darkorange">magic comment</font> must be placed into the source files either as first or second line in the file</p>
    
    <p><sup>（「PEP 263 <a href="https://www.python.org/dev/peps/pep-0263/#defining-the-encoding">Defining Python Source Code Encodings</a>」 @ PEP より、赤字は筆者）</sup></p>
    
    <p>【筆者訳】</p>
    <p>ソースコードのエンコーディングを定義するには、ソースファイルの 1 行目もしくは 2 行目に<font color="darkorange">マジックコメント</font>を設置する必要があります</p>
    
    </blockquote>
    
    Ruby などの「マジックコメント[^ruby]」と同様なようです。しかし、Python の公式文献（日本語版）には、**具体的な和名は見つかりません**でした。
    
    <blockquote>
    <ul>
    <li>ソースコードの文字コード指定の特別なコメント</li>
    <li>ソースコードのエンコーディング</li>
    <li>文字セットエンコーディングの宣言</li>
    </ul>
    
    <p>
    <sup>（「<a href="https://docs.python.jp/3/tutorial/interpreter.html#source-code-encoding">ソースコードの文字コード</a>」| インタプリタとその環境 @ Python3 公式マニュアル より）</sup><br>
    <sup>（「<a href="https://docs.python.jp/3/whatsnew/2.3.html#pep-263-source-code-encodings">PEP 263: ソースコードのエンコーディング</a>」| What’s New in Python 2.3 @ Python2 公式マニュアル より）</sup>
    </p>
    
    </blockquote>
    
    「特別なコメント」が「<code>magic comment</code>」の訳だと思いますが、<code>magic</code> の訳し方が難しかったのだと思います。
    
    「ソースコードに魔法のコメントで文字コードを指定します」だと微妙、みたいな。「おいしくなぁれ」のような謎の仕様に思われるからでしょうか。
    
    普通に「文字コード指定」「エンコーディング指定」「エンコーディング宣言」「文字セットエンコーディングの宣言」などで通じそうです。深く考えすぎてしまいました。
    
    コンピューターの世界では「何を言っているのかわからないも、唱えると動いちゃうし、むしろそれがないと正常に動かない」系のものを「マジックなんとか」と呼ぶ習慣があります。[マジックナンバー](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%B8%E3%83%83%E3%82%AF%E3%83%8A%E3%83%B3%E3%83%90%E3%83%BC_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0))などは有名です。しかし、ドキュメントにそこまで説明的に書くのはナンセンスですし「初心者に優しい言語」と、うたっている Python ゆえの葛藤だったのかもしれません。知らんけど。
    
    ---
    
    </div></details>

- **Python 3 の場合、ソースが UTF-8 の時は記載は不要**<br>（[PEP-8](https://pep8-ja.readthedocs.io/ja/latest/#id12) では<font color="darkorange">むしろ**記載は非推奨**</font> 😱）
  - Python **2** の場合、ソースが UTF-8 の時は逆に記載が必須
- 文字コード宣言を記載する場合：
    - 1 行目 or 2 行目に記載すること
    - 以下の**いずれの記述方法でも構わない<sub><sup>（その理由は[後述](#%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89%E5%AE%A3%E8%A8%80%E3%81%AE%E4%BB%95%E6%A7%98)）</sup></sub>**。
        - `# coding: [encoding]`
        - `# coding:[encoding]`
        - `# coding=[encoding]`
        - `# coding= [encoding]`
        - `# -*- coding: [encoding] -*-`<sub><sup> （Emacs 併用）</sup></sub>
        - `# -*- coding:[encoding] -*-` <sub><sup>（Emacs 併用）</sup></sub>
        - `# vim:fileencoding=[encoding]` <sub><sup>（Vim 併用）</sup></sub>
- `[encoding]` 部分の仕様
  - 正規表現 `([-\w.]+)` にマッチすること
      - `-` `a-z` `A-Z` `0-9` `_` `.` の連続文字列
      - `_` は `\w` の正規表現に含まれています。（詳しくは[コメント](#comment-2620fa90e1838d068690)参照）
  - **大文字・小文字は問わない**
- `[encoding]` 部分で**指定可能な UTF-8 の一覧**（エイリアス含む）
  - `utf8`, `utf-8`, `utf_8`, `u8`, `utf`, `cp65001`
- Python3 ソースコードのエンコーディング指定で<font color="darkorange">**利用可能な文字コード名一覧**</font>
  - [Standard Encodings](https://docs.python.org/3/library/codecs.html#standard-encodings) | Codecs | Library @ Python3 公式ドキュメント（英語版）

### PEPとは

<details><summary>PEP の基本概要</summary><div>

<h4>PEPとは何か？</h4>

<p>公式のガイドラインには以下のような説明があります。</p>

<blockquote>
<p>PEP は Python 拡張提案（<code>Python Enhancement Proposal</code>）を表しています。PEP は Python のコミュニティに対して情報を提供したり、Python の新機能やプロセス、環境などを説明するための設計書です。PEP は、技術的な仕様と、その機能が必要な論理的な理由を提供しなければなりません。</p>
<p>我々は、PEP を、新機能を提案したり、課題に関するコミュニティの意見を集約したり、Python に取り込まれることになる、設計上の決定をドキュメント化するための、主要なメカニズムであると位置づけています。PEP の作者は、コミュニティの中でコンセンサスを取ったり、反対意見の記録を取る責任を持ちます。</p>
<p>PEP はテキストファイルの形式でバージョン管理されたリポジトリの中に保管されます。そのリポジトリの変更履歴は、機能提案の経緯の記録となります。</p>
<p><sup>（PEP-0001「<a href="http://sphinx-users.jp/articles/pep1.html">PEPの目的とガイドライン（日本語訳）</a>」@ Sphinx の日本ユーザ会 より）</sup></p>
</blockquote>

<p>なかなか、何を、言っているか、わからない、感じの、説明です。</p>
<p>一言で言うと「PEP は Python の<a href="https://ja.wikipedia.org/wiki/%E6%A8%99%E6%BA%96%E5%8C%96">スタンダード</a>（標準）をまとめたもの」です。</p>
<p>つまり、<a href="https://ja.wikipedia.org/wiki/%E5%9B%BD%E9%9A%9B%E6%A8%99%E6%BA%96%E5%8C%96%E6%A9%9F%E6%A7%8B">ISO</a>・<a href="https://ja.wikipedia.org/wiki/IEEE_Standards_Association">IEEE</a>・<a heref="https://ja.wikipedia.org/wiki/World_Wide_Web_Consortium">W3C</a> のような、<strong>Python における各種スタンダード（標準化された規格）が制定されたもの</strong>が取りまとめられた、いわば Python の<a href="https://qiita.com/KEINOS/items/cb7f629268b90ef6493d">プロトコル</a> CODE です。</p>
<p>例えば「Python の<a href="https://www.python.org/dev/peps/pep-0008/">コーディング規約は PEP-8 で制定</a>されている」といった具合です。そのため、何かの仕様や新しい機能が追加・変更される（拡張される）場合に PEP を通して制定されます。</p>
<p>PHP の <a href="https://en.wikipedia.org/wiki/PHP_Standard_Recommendation">PSR</a> のようなものですが、外部団体でなく Python 自体が制定しているので「Python はコードが読みやすい」理由にもなっているのかもしれません。最初から整頓されていて、さすが Python パイセン。PHP より年上とは思えない几帳面さ。</p>

<ul>
<li>参考文献</li>
  <ul>
    <li>PEP-0008「<a href="https://pep8-ja.readthedocs.io/ja/latest/#">Python コードのスタイルガイド（日本語訳）</a>」@ ReadTheDocs</li>
  </ul>
</ul>

<hr>

</div></details>

### ミッフィーちゃんみたいなやつ

`(・×・)` のような顔文字っぽいのは薄っすらと覚えているのです。

さすがに <ruby><sup><sub>(・×・)</sub></sup><rt>⋂ ⋂</rt></ruby> ではないとわかるも、それが `-*-` だったか `_*_` だったか `(⊃*⊂)` だったか思い出せないのです。

文字コードの指定方法も `/*-utf-8-*/` だったか `lang=ja_JP.utf-8` だったか `encode=utf-8` だったかすらも思い出せないのです。

そこで、パーツを２つにわけて覚えようとしました。「前後の記号」部分（A）と「エンコード指定」部分（B）です。

```python:前後の記号部=A、エンコード指定部=B
[A] [      B        ] [A]
-*- coding=[encoding] -*-
```

まずは「前後の記号」（A の `-*-` の部分）です。

> 「迫るパイソンに、冷静に[口を開いて<ruby>威嚇<rt>いかく</rt></ruby>するミッフィー](https://togetter.com/li/1267263)」
> `-x-`（威嚇前）→ `-*-`（威嚇中）

せっかく覚えたのですが、「エンコード指定部」の<ruby>文言<rt>もんごん</rt></ruby>（ B の`coding: utf-8` の部分）を調べていくうちに <font color="darkorange">**[Emacs](https://ja.wikipedia.org/wiki/Emacs) ユーザーでない場合はミッフィーちゃんは不要**</font>であることがわかりました。

どうやら、<font color="darkorange">**`-*- coding: ... -*-` と書くのは Emacs 互換のための記述**</font>のようです。

しかも、GNU Emacs も [v23 からデフォルトエンコーディングが UTF-8](https://lists.gnu.org/archive/html/info-gnu-emacs/2009-07/msg00000.html) になりました。

- 参考文献
    - 「[ファイル中に明示的に文字コード指定を埋め込む (`-*- coding: utf-8; -*-`)](http://emacs.clickyourstyle.com/articles/299)」| emacs @ MediaHub
    - [PEP 3120 -- Using UTF-8 as the default source encoding](https://www.python.org/dev/peps/pep-3120/) | PEP @ Python.org
    - Ruby 「[衝撃の事実!? `# -*- encoding: utf-8 -*-`じゃなくてもいいんです！](https://qiita.com/jnchito/items/8f44a3c52d4669fefa93)」@ Qiita
    - [Choosing File Modes](https://www.gnu.org/software/emacs/manual/html_node/emacs/Choosing-Modes.html#Choosing-Modes) | Modes | Manual @ GNU Emacs
    - [Emacs 23.1 released](https://lists.gnu.org/archive/html/info-gnu-emacs/2009-07/msg00000.html) | Archive | Lists @ GNU Emacs

### 文字コード宣言の仕様

残念ながら「ミッフィーちゃんは必須ではない」らしい情報は得たものの、続けて「エンコード指定」の部分を調べていると、**同じ UTF-8 でも人によって書き方にバラツキがある**ことに気付きました。

- `coding=utf8`
- `coding=utf-8`
- `coding:utf-8`
- `coding:utf8`
- `coding: utf8`
- `coding=utf_8`
- `coding:utf_8`
- `encoding:utf-8`
- `encoding:UTF8`
- etc...

どうやら、これも覚えられなかった一因のようです。むしろ「ウォーリーを探せ」くらいの微妙な違いです。（実は、このことが検証時にさらなる悲劇を生むことになります。こうご期待）

そこで、**仕様的に正しくはどう書くのか調べた**ので報告いたします。

> If a comment in the first or second line of the Python script matches the regular expression `coding[=:]\s*([-\w.]+)`, this comment is processed as an encoding declaration;
>
> <sup>（[Encoding declarations](https://docs.python.org/3/reference/lexical_analysis.html#encoding-declarations) | Lexical analysis @ 英語版公式 Python3 言語リファレンスより）</sup>
>
> 【筆者訳】
> Python スクリプトの 1 行目または 2 行目のコメントが正規表現 `coding[=:]\s*([-\w.]+)` にマッチした場合、このコメントはエンコーディングの宣言文として扱われます。

上記仕様によると、Python では以下の２つの条件にマッチすると「文字コード指定行」と判断されます。

1. １行目もしくは２行目のコメント行であること
2. 「`coding[=:]\s*([-\w.]+)`」の正規表現にマッチすること

    <details><summary>正規表現の説明</summary><div><br>
    
    コメント行は Bash で言う `head -2 | grep -e "^#"` と同等で、最初の 2 行のうち `#` から始まるものをコメント行として扱います。そしてコメント行を正規表現でチェックします。
    
    「`coding[=:]\s*([-\w.]+)`」の正規表現の意味は以下の通りです。
    
    - `coding[=:]`
        - `coding=` もしくは `coding:` を含む
        - `Coding:` など**大文字で始まるとマッチしないので注意**
    - `\s*`
        - 0個以上のスペースが続く
    - `[-\w.]+`
        - `-` `[a-zA-Z]` `[0-9]` `_` `.` の任意の１つ以上の連続文字。これがエンコード名。
        - `_` は `\w` の正規表現に含まれています。詳しくは[コメント](#comment-2620fa90e1838d068690)参照。
    
    ---
    
    </div></details>

つまり、**仕様上は `-*-` は必要ない**のです。

これがミッフィーちゃんが不要な理由です。逆に言えば以下の指定でも動いてしまうということです。

```
# 💩💩💩💩 uncoding=utf-8 💩💩💩💩
```

- <sub><sup>本当に動いちゃう例を[オンラインで見る](https://paiza.io/projects/06MYpapQLjKg0FBhp-IRVw) @ paiza.IO</sup></sub>

同様に、これが [Vim](https://ja.wikipedia.org/wiki/Vim) 併用の記述としても使える理由です。

```
# vim:fileencoding=utf-8
```

また検証の結果、文字コードの `UTF-8` `utf-8` の**大文字・小文字は区別しません**でした。調べたところ、内部で小文字に変換しているそうです。（後述）

となると不思議な点が出てきます。

`coding[=:]\s*([-\w.]+)` の仕様はわかったのですが、`utf_8` のように `_`（アンダースコア、アンダーバー）を使った記述はどうなっているのでしょうか。

### Python3 のソースコードのエンコーディングで利用可能な文字コード名

#### UTF-8 と UTF_8 の違い

先に結論から言うと<strong>「UTF-8」も「UTF_8」も違いはありません</strong>。内部で変換されてから正規表現を通して `utf_8` と認識されるためです。

しかし、<strong>「正しくは（仕様的には）どちらで書いた方が好ましいのか」気になった</strong>ので続けて調べてみました。

日本語の Python リファレンスには以下のように書かれています。

> エンコーディングが宣言される場合、そのエンコーディング名は Python によって認識できなければなりません。宣言されたエンコーディングは、例えば文字列リテラル、コメント、識別子などの、全ての字句解析に使われます。
> 
> <sup>（「[エンコード宣言（encoding declaration）](https://docs.python.org/ja/3/reference/lexical_analysis.html#encoding-declarations)| 字句解析」@ 公式 Python3 言語リファレンス より）</sup>

「エンコーディング名は Python によって認識できなければなりません」とあるのですが、**どのようなものが認識されるのか明記されていません**でした。（2020/10/27 現在）

しかし、英語の方の公式 Python3 のドキュメントには、より具体的な記述がありました。

> To declare an encoding other than the default one, a special comment line should be added as the first line of the file. The syntax is as follows:
>
> ```python
> # -*- coding: encoding -*-
> ```
> where encoding is one of the valid [codecs](https://docs.python.org/3/library/codecs.html#module-codecs) supported by Python.
>
> <sup>（[Source Code Encoding](https://docs.python.org/3/tutorial/interpreter.html#source-code-encoding) | The Interpreter and Its Environment | 英語版公式 Python3 チュートリアル より）</sup>
>
> 【筆者訳】
> デフォルト以外のエンコーディングを宣言するには、ファイルの1行目に特別なコメント行を追加する必要があります。構文は以下の通りです。
>
> ```python
> # -*- coding: [encoding] -*-
> ```
> ここでの "encoding" は、Python でサポートされている有効な[コーデック](https://docs.python.org/3/library/codecs.html#module-codecs)を指定します。

とリンク付きであります。

さらに英語版の方では、ありがたいことに「ソースコードの文字コードが `Windows-1252` の場合、`encoding` 部分は `cp1252` であるべき」というサンプルも記載されていました。

> For example, to declare that Windows-1252 encoding is to be used, the first line of your source code file should be:
>
> ```python
> # -*- coding: cp1252 -*-
> ```
>
> <sup>（[Source Code Encoding](https://docs.python.org/3/tutorial/interpreter.html#source-code-encoding) | The Interpreter and Its Environment | 英語版公式 Python3 チュートリアル より）</sup>
>
> 【筆者訳】
> 例えば、Windows-1252 エンコーディングを使用することを宣言するには、ソースコードファイルの 1 行目を以下のように記述します。
>
> ```python
> # -*- coding: cp1252 -*-
> ```

つまり、この `codecs` の対応表を探せば「**Python3 のソースコードのエンコーディングで利用可能な文字コード名**」とやらがわかりそうです。

ちゃんとライブラリのドキュメントの `codecs` 欄に対応表の一覧がありました。

そこから URL をいじって日本語版を開いてみます。

- Python3 のソースコードのエンコーディングで利用可能な文字コード名
  - [Standard Encodings](https://docs.python.org/3/library/codecs.html#standard-encodings) | Codecs | Library @ Python3 公式ドキュメント（英語版）
  - [標準エンコーディング](https://docs.python.org/ja/3/library/codecs.html#standard-encodings) | Codecs | Library @ Python3 公式ドキュメント（日本語版）

:::note info
🐒&nbsp;Python のドキュメントは整頓されているものの、意外に探しづらい気がするのは筆者だけでしょうか。情報の並びが東急ハンズに見えるのに、ドンキーで探し物をしているような印象を受けます。
:::

| Codec | Aliases | Languages |
|:--|:--|:--|
| ... | ... | ... |
| utf_8 | U8, UTF, utf8, cp65001 | all languages |
| ... | ... | ... |

なんと、ここで UTF-8 の内部コーデック名が `utf_8` と `_`（アンダースコア）で指定されています。また、[エイリアス](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%82%A4%E3%83%AA%E3%82%A2%E3%82%B9)として別名でも指定できることがわかりました。

つまり `U8` や `utf8` や `cp65001` と指定しても、内部で `utf_8` に変換されるということです。

しかし、エイリアスの一覧に `utf-8` の `-`（ハイフン）の記述がありません。

**謎は深まるばかり**です。

すると、一覧の上にサラっと以下の一文が記載されていました。

> Notice that spelling alternatives that only differ in case or use a hyphen instead of an underscore are also valid aliases; therefore, e.g. `'utf-8'` is a valid alias for the `'utf_8'` codec.
>
> 【筆者訳】
> 注意点として、エイリアス以外で<ruby>つづり<rt>・・・</ruby></ruby>の違いが有効なのは、「大文字と小文字の違い」と「アンダースコア（`_`）の代わりにハイフン（`-`）を使用する場合」のみです。したがって、たとえば `'utf-8'` は `'utf_8'` コーデックの有効なエイリアスとなります。

つまり、**`-`（ハイフン）は `_`（アンダースコア、アンダーバー）に変換されるということ**です。

以上を踏まえると、<font color="darkorange">`utf-8` と `utf_8` なら、`utf_8` と記載した方が良い</font>ことになります。置換処理を必要としないストレートな処理ができるためです（ゆうて大した速度の違いはないのですが）。

#### 大いなる誤解

実は、[以前の記事の版](https://qiita.com/KEINOS/items/6efc1147b917d7811b5b/revisions/117?type=preview)では「`_` は使わずに `-` を使え。Python2 で `coding:utf_8` で動くのはたまたま」と言っていました。しかも、律儀に[検証実証](https://paiza.io/projects/Z93ql0uz5vhjvw9HYtb96g)まで添えて。

というのも、`coding[=:]\s*([-\w.]+)` の正規表現には `_` が含まれないと勘違いしていたのです。`\w` の正規表現は`word` の `w` だから `[a-z][A-Z][0-9]` だけだと[重いコンダラ](https://ja.wikipedia.org/wiki/%E6%95%B4%E5%9C%B0%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC#%E4%BF%97%E7%A7%B0%E3%80%8C%E3%82%B3%E3%83%B3%E3%83%80%E3%83%A9%E3%80%8D)状態だったです。

ところが、[コメント](#comment-2620fa90e1838d068690)を読んでビックリしました。

... そう ... 実は小生、`_` の挙動を色々と[検証している](https://paiza.io/projects/Z93ql0uz5vhjvw9HYtb96g)中で、ずーっと `coding` を `codeing` と typo していたのでごザルよ！！そりゃ動かないわな！

|![スクリーンショット 2022-01-15 16.08.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/ae3dea2c-9a11-0972-874b-1abf51db1f43.png)|
| :-- |
| ザルな検証のしすぎで、検証猿でごザルの例 |

そこで、確認のために公式ドキュメントを読むと、なんと！Python の正規表現の `\w` には `_`（アンダースコア、アンダーバー）も含まれていると明記されているじゃぁないですか！！

> **`\w`**
> Unicode (str) パターンでは:
> Unicode 単語文字にマッチします。これはあらゆる言語で単語の一部になりうるほとんどの文字、数字、およびアンダースコアを含みます。ASCII フラグが使われているなら、 [a-zA-Z0-9_] のみにマッチします。
> <sub><sup>（[正規表現のシンタックス](https://docs.python.org/ja/3/library/re.html#index-32) | re --- 正規表現操作 | v3 | JA @ docs.python.org より）</sup></sub>

ここでもドキュメント嫁にしかられてしまいました ... ... よくよく考えてみれば PHP の `word character` も同じ `letter, number, underscore` でした。とほほ。

このように、`coding:utf_8` でも動いてしまう理由は「たまたま」ではなく、`\w` の正規表現に `_` が含まれていることと、`-` が `_` に置換されるからでした！ > @JsM さん、ありがとう！

#### まとめ

まとめると、渡されたエンコーディング名は前処理として以下を行い、**`codec` と完全一致した場合に有効なエンコード指定と判断される**ということです。

1. コメント行の 1 〜 2 行目を取得する
1. 正規表現でフィルターをかける
1. 小文字に変換する
1. `-` は `_` に変換される
1. `Aliases` 一覧にマッチした場合は、対応する `Codec` に置換する
1. 変換/置換後の結果が `Codec` 一覧のいずれかにマッチした場合は有効なエンコード指定とする

今度は、ちゃんとした実証実験として、`# coding:utf_8` と宣言した Python ファイルを Python2 で実行すると、ちゃんと動きました！

```shell-session
$ python3 sample.py
これはUTF-8ですよ

$ python2 sample.py
これはUTF-8ですよ
```
- [オンラインで動作をみる](https://paiza.io/projects/5e-GRJrTo4L1ihn3I69ubg) @ paiza.IO
- [typo 版をオンラインでみる](https://paiza.io/projects/Z93ql0uz5vhjvw9HYtb96g) @ paiza.IO

### 文字コードを記載しない人たちの理由 <sub><sup>（PEP-8に準拠している人たち）</sup></sub>

さて、文字コードについて完全に理解したつもりでいたところ、「そもそも文字コードを指定していないソースコード」も見かけました。

「（おいおい。そんな装備で大丈夫かぁ）」とニヤニヤしながら調べたところ、そもそも **Python3 では UTF-8 の場合は文字コードは指定しないことが推奨されている**ことがわかりました。

> PEP8を読んでいたらこんな記述に気づいた。
>
>> ASCII (Python 2) や UTF-8 (Python 3) を使用しているファイルにはエンコーディング宣言を入れるべきではありません。
>> [はじめに — pep8-ja 1.0 ドキュメント](http://pep8-ja.readthedocs.io/ja/latest/#id12)
>
> 　えぇぇぇぇ！？　と思ったんだけど、何回読み直しても「デフォルトエンコーディング使うならエンコーディング宣言は書くなよ！」と書いてあるようにしか読めない。
> 
> （「[# coding: utf-8はもうやめる](https://www.haya-programming.com/entry/2018/04/23/163159)」 @ 静かなる名辞 より）

マスオさんどころか、私も<ruby>ビックリ<rt>えぇぇぇぇ!?⤴️</rt></ruby>です。

確かに、[リンク先のドキュメント](http://pep8-ja.readthedocs.io/ja/latest/#id12)や PEP-8 の[英語の原文](https://www.python.org/dev/peps/pep-0008/#source-file-encoding)を読んでも、「Python2 の場合 ASCII、Python3 の場合 UTF-8 で書かれたソースコードでは**文字コードの宣言文はいれない**」という規約があるようです。（[コメントも 120% の確信がなければ日本語も不可](https://www.python.org/dev/peps/pep-0008/#comments)って随分と厳しいルールですね。まぁ、レベルが `should` 以下なので絶対というわけではないですけど）

[Python3 の公式マニュアル](https://docs.python.jp/3/tutorial/interpreter.html#source-code-encoding)では、「`デフォルトでは、Python のソースコードは UTF-8 でエンコードされているものとして扱われます。`」とあります。

そのため、UTF-8 の場合は基本的に不要というのはわかりました。そして、Python2 の場合は、デフォルト・エンコードが ASCII であるため、逆に UTF-8 の場合は必須ということです。

おそらく、名著とされる本でも文字コードを書くように勧めるのは、Python2 から Python3 への過渡期であるいま、両バージョンを網羅しないといけないからなのかもしれません。また、SJIS-win から UTF-16 への移行過渡期にある Windows ユーザーのことも考えて[ポカヨケ](https://ja.wikipedia.org/wiki/%E3%83%9D%E3%82%AB%E3%83%A8%E3%82%B1)として記載させているのかもしれません。

PHP4 時代、メール送信の実装で[ガラケー](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%BC%E3%83%81%E3%83%A3%E3%83%BC%E3%83%BB%E3%83%95%E3%82%A9%E3%83%B3)対応など、混沌とした文字コードを吸った揉んだしようとしたホロ苦い経験から、**内部では UTF-8 で処理を統一して、出力時に文字コードを変換する**というプラクティスがありました。そのため、むしろ Python3 の UTF-8 がデフォルトというのはシックリと来ます。

さて、ここまで調べた結果の結論を言うと、Python3 で行くと決めたし、UTF-8 で統一しているから<strong><font color=darkorange>「冒頭に記載するアレ」は不要</font></strong>という、ナンタルチアな答えに。とほほ。

- 参考文献
    - [PEP-0263](https://www.python.org/dev/peps/pep-0263/) | PEPs | dev @ python.org
    - [PEP-0008](https://www.python.org/dev/peps/pep-0008/) | PEPs | dev @ python.org
    - [Python のコーディング規約 PEP8 に準拠する](https://qiita.com/ynakayama/items/8616f4c0c6e372de9a42) @ Qiita
    - [# coding: utf-8はもうやめる](https://www.haya-programming.com/entry/2018/04/23/163159) @ 静かなる名辞
    - [ソースコードの文字コード](https://docs.python.jp/3/tutorial/interpreter.html#source-code-encoding) | Python インタプリタを使う @ 公式 Python3 チュートリアル
    - [Pythonのcoding: ﾅﾝﾄｶのことがよく分からないから調べてみた](https://qiita.com/ronin_gw/items/2c82b727461b18991eff) @ Qiita


## あわせて読みたい

- [Python 3の各種エンコーディングについて](https://qiita.com/methane/items/6e294ef5a1fad4afa843) @ Qiita

## その他参考文献

[^ruby]: [magic_comment](https://docs.ruby-lang.org/ja/latest/doc/spec=2fm17n.html#magic_comment) | 多言語化 @ Ruby 公式ドキュメント