Python 3 の変数名に使える文字たち

# きっかけ
Python 3 では変数や関数の名前にASCII文字以外が使えるので、たとえばこんな風にコードを書くことができます。

```py3

import numpy as np

def σ(a):
    return 1 / (1 + np.exp(-a))

φ = np.array([1, 0, 1])
w = np.array([1, -1, 0.5])
σ(np.dot(φ, w))
```

ちょっとだけ数式っぽくないですか？
今まで `phi` って書いてたのが `φ` ってそのまま書けるんです！

今まで予約語の `lambda` と被らないように `LAMBDA` とか `l` とか書いて回避してたのを `λ = 0.5` って書けたらうれしくないですか！

ってなると、
「わーい！ギリシャ文字とかいっぱい使いたい！」
ってなりますよね？

# 問題
ところが、、、

```py3

>>> ∆ = 100
File "<ipython-input-24-46dfc697fb0a>", line 1
    ∆
    ^
SyntaxError: invalid character in identifier
>>> 🍣 = 1000
  File "<ipython-input-24-46dfc697fb0a>", line 1
    🍣 = 1000
    ^
SyntaxError: invalid character in identifier
```
全部が全部好きな文字を使えるってわけではないんです.............

# 変数名に使える文字

ってことで変数名に使える文字と使えない文字を総当たりしてみました。

```py
from collections import defaultdict
import unicodedata


ok_chars = defaultdict(list)
ng_chars = defaultdict(list)


for i in range(0x10FFFF):
    if i == 35:  # sharp (#)
        continue
    try:
        exec("%s = 1" % chr(i))
        ok_chars[unicodedata.category(chr(i))].append(chr(i))
    except:
        ng_chars[unicodedata.category(chr(i))].append(chr(i))
        continue

for char_type in (set(ok_chars) | set(ng_chars)):
    print(char_type, len(ok_chars[char_type]), len(ng_chars[char_type]))
```

太字のもの以外はほとんど使えないと思ってよさそう。

| カテゴリ日本語名 | カテゴリ | 使える文字の数 | 使える例 | 使えない文字の数 |  使えない例 |
| --- | --- | --- | --- | --- | --- |
| **大文字アルファベット** | Lu | 1631 | A, B, Ə, Ɵ, Ʈ, Ƴ, Δ, Σ | 0 | |
| **小文字アルファベット** | Ll | 1967 | a, b, ə, ɵ, γ, δ, ε| 0 | |
| **数値を表す文字** | Nl | 235 | Ⅶ ⅻ 〨 ↂ| 0 |  |
| **その他の文字** | Lo | 105679 | あ 鬱 众 줦 ཫ | 18 | ำຳﱞﱟﱠﱡﱢﱣﷺﷻﹰﹲﹴﹶﹸﹺﹼﹾ |
| **擬似文字** | Lm | 242 | ₔ 〻 々 〳 ꟹ | 4 | ͺⸯﾞﾟ |
| タイトル文字 | Lt | 31 | ǅ ǈ ǋ ᾈ  | 0 | |
| 他の文字を修飾するための文字 | Mn | 0 |  | 1567 | '͚ '͛ '͜ '͝ |
| 修飾文字 | Mc | 0 | | 383 | ௌௗఁంః |
| 数学記号 | Sm | 1 | ℘ | 947 | ± × ÷⅀  ⅁ ⅂ ∂ ∃ ∄|
| その他の記号 | So | 1 | ℮ | 5676 | ⏩  ⏰ ⌦  ℻ |
| 通貨記号 | Sc | 0 |  | 53 | $ ¢ £' ￠ ￡ ￥ ￦|
| その他の数字 | No | 0 |  | 647 | ⑧ ㈦ ⅐ ൱|
| 未定義コードポイント | Cn | 0 | | 853858 | ͸ ֋ |
| 私的利用領域 | Co | 0 | | 137468 |   |
| 10進数字 | Nd | 0 | | 550 | 0 1 ٦ ੩ ၃ ８ |
| その他の句読記号 | Po | 0 | | 512 | # ! 、 。¶ ༄ |
| 開き句読記号 | Ps | 0 | | 75 | ( ｢  ︗ ⸨|
| 閉じ句読記号 | Pe | 0 | | 73 | ] } 》 」 』 】 〕|
| 合わせ文字 | Sk | 0 | | 121 | ＾ ｀ ￣ 🏻 |
| 他の文字を囲むための文字 | Me | 0 | | 13 | '҈ '҉ '᪾ '⃝ '⃞ '⃟ '⃠ '⃢ '⃣ '⃤ '꙰ '꙱ '꙲ |
| ダッシュ | Pd | 0 | | 24 | - ֊ ־ ᐀ ᠆ ‐ ‑ ‒ – — ― ⸗ ⸚ ⸺ ⸻ ⹀ 〜 〰 ゠ ︱ ︲ ﹘ ﹣ －|
| 先頭句読記号 | Pi | 0 | | 12 | « ‘ ‛ “ ‟ ‹ ⸂ ⸄ ⸉ ⸌ ⸜ ⸠ |
| 末尾句読記号 | Pf | 0 | | 10 | » ’ ” › ⸃ ⸅ ⸊ ⸍ ⸝ ⸡ |
| 連結用句読記号 | Pc | 1 | _ | 9 | ‿ ⁀ ⁔ ︳ ︴ ﹍ ﹎ ﹏ ＿ |
| 空白文字 | Zs | 0 | | 17 |        |
| サロゲート | Cs | 0 | | 2048 | |
| コントロール文字 | Cc | 20 | | 65 |
| 非可視整形用文字 | Cf | 0 | | 150 | |
| 段落区切り文字 | Zp | 0 | | 1 |  |
| 行区切り文字 | Zl | 0 | | 1 |   |

# 関数/クラス名に使えない文字

↑のコードのexec文を `exec("def %s(): pass" % chr(i))` にすると関数名に使える文字もチェックできます。
差分は、コントロール文字が全部使えなくなってるくらい (そもそも使わないからどうでもいい)
クラス名も同じ結果。

# 使えてうれしい文字

本来の目的である数値計算を読みやすくするのに使える文字はこれ！

```
αβγδεζηθικλμνξοπρςστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩƏ ᐁ
```

ギリシャ文字だけ。
ドヤるほどでもなかった..........。

適当にネットで文字をコピペすると
Δ (U+394; GREEK CAPITAL LETTER DELTA) と ∆ (U+2206; INCREMENT)
を間違える悲劇が起きたりするので↑からコピペするとよさげ。
ちなみにラプラシアンも変数として使えないです。

# まとめ

Python3では変数/関数/クラス名にUnicode文字が使える
けど、全部の文字が使えるわけではない (使えない文字多い)。
数値計算に使えそうな文字はギリシャ文字くらい。

Unicode名の変数/関数を使うメリットは論文や教科書の数式とコードとの対応が取りやすくなることです。職業プログラマー的な視点からだと「Unicode名を使うなんてとんでもない」って思われそうだけど、業務コードじゃなくて勉強目的、「PRML勉強会でロジスティック回帰をコードに落としこみました」みたいなときによさそうだと思います。

というわけで Python 3 を感じずにはいられない話でした...†