【なんでなん】pythonコマンド叩いたらPermission deniedしたけどPYコマンドで動いた

#はじめに

最近Atcoderを始めようとしてローカルにpythonの環境を作ろうとVs Codeとpythonをインストールしたんですよ。
それで、適当なファイルを試しに実行してみようと思って以下のようなコマンドをうってみたんですね。

```
python PythonApplication1.py
```

そしたら以下のようなエラーになったわけです。

```
bash: /c/Users/ユーザープロファイル/AppData/Local/Microsoft/WindowsApps/python: Permission denied
```

それで、まぁ権限がないのかなーと思って調べてみたら、「python」ではなくて「PY」で通るよという情報を見つけたんですね

```
PY PythonApplication1.py
```

そしたら見事に動くわけですよ。
こりゃどういうことだと思って調べてみました。

#なぜ動かないのか

通常コマンドを実行する際に頭につける「python ~」みたいなやつって、そこに紐づけられたソフトウェアを動かしているんですけど、pythonの場合は「python.exe」というものを動かしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540428/7c097bcc-fa54-5ced-6111-2b9db06f6a48.png)

今回のエラーはbash: /c/Users/ユーザープロファイル/AppData/Local/Microsoft/WindowsApps/python: Permission deniedなので「/c/Users/sasak/AppData/Local/Microsoft/WindowsApps/python.exe」にアクセスしようとして権限がないというエラーでした。
このディレクトリでコマンドプロンプトを開いて直接「python」と実行するとエラーにはならないので、おそらくこれはvscodeからの実行に対して権限を付与していないんだろうなあと思います。

ただ、このpython.exeってどうやらデフォルトで入っているもので、機能としてはストアを開くだけしかできないんですよね。
つまりこれが実行できたところで何も起きないのです。
本当にちゃんと動くのは以下のような場所の奴ですね

```
C:\Users\ユーザプロファイル\AppData\Local\Programs\Python\Python38\python.exe
```

ただ僕のPCには上記のような場所にpythonが無かったので、PYを指定したとしても動くpythonないやんなぁと思ったのですが、もうちょっと調べてみたら以下の場所にpythonが入ってました

```
C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64
```

あーVisual Studioで入れた時の奴が動いてたんですね。
なんて複雑な環境になってしまっているんだ...
ためしにアンインストールしてみたところ当然ですが動かなくなりましたね。

```
$ PY --version
Can't find a default Python.
```

# PYってなんだ

PYはpy.exe（パイソンランチャー）を実行しています。
Pythonランチャーは、pythone.exeへのPATHが通っていなくても使用可能で、windowsにおけるpython3.3以上のインストールでくっついてきます。
windowsではデフォルトで.pyを起動する際にpy.exeが使われるように設定されているため、pyファイルをダブルクリックして動作するのもこれになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540428/55a79d57-1adc-63a6-9447-3cbbf2c87afe.png)

Pythonはとても使いやすく便利な言語として知られていますが、欠点としてversion管理があげられます。
これは、python2.xで書いたコードをpython3.xで動かそうとすると問題が起きたりするので、過去に使用していたすべてのversionを残したまま、実行するコードによってpythonのどのversionで実行するかを切り替える必要があるということです。
pythonコマンドを実行する場合、python.exeもversionごとに存在するため、python2.7を実行する場合はpythonコマンドで動くようにして、python3.2を実行する場合はpython3コマンドで動くようにして...というような複雑な管理が必要でした。
これらを解決するため、複数versionを管理するpyenvなどのモジュールも作成されました。

この問題をwindowsで解決してくれるのがpy.exeです。
Pythonランチャーは、複数のバージョンが存在していても、最新バージョンで実行してくれます。
しかし、「今までバージョン3.5を使用していて、3.6にグレードアップしたら、一部のPythonプログラムが動かなくなった。動かなくなったプログラムだけは、3.5のまま使用したい。」という場合もあります。
この場合は、プログラムファイルの先頭に追記することで、それをpy.exeが読み取って実行バージョンを変えてくれます。
このPythonプログラムファイル（*.py）をダブルクリックすると、Pythonランチャーがこの先頭行を解釈して、3.5で実行してくれます（3.5はインストールされている必要があります）。
この#!で始まる行は、Shebang（シバンまたはシェバン）と呼ばれ、元はUnix系システムにおいて、実行するプログラムを指定するのに使われていますが、WindowsではPythonランチャーが擬似的に解釈してくれます。

```
#!python3.5
```

コマンドで指定することも可能です。
以下のようにpyの後にバージョンを指定します。
先頭行のShebangでもバージョンが指定されている場合は、コマンドの方が優先されます。つまり、sample.pyの先頭に、#!python3.3と入力されていても、コマンドでは3.5で実行されます。

```
C:¥Works¥py> py -3.5 sample.py
```

プログラム実行時はshebangで指定することが多いですが、pipを使う場合にはコマンドで切り替えます。
例えば、3.5と3.6がインストールされている環境で、旧バージョンの3.5の方にライブラリをインストールする場合は、以下のようにバージョンを明示する必要があります。

```
py -3.5 -m pip install pypdf2
py -m pip install pypdf2  <= 3.6の方にインストールされる
```

既にPATHにpythonが登録されている場合は、pythonとpyで違うバージョンを指してしまうので、pipを使う場合などは注意が必要です。

```
pip install pypdf2       <= Python 3.5にインストールされる
py -m pip install pypdf2 <= Python 3.6にインストールされる
```

pythonのpathはインストール時に以下にチェックを入れると勝手に登録されますが、デフォルトでも外れていますし、バージョンの指定も面倒なので、PYで常に動かすという前提でもよいでしょう。
その場合は、pathに登録する必要もありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540428/17d272c1-0426-19ee-4360-8989dc7ea9e7.png)


#まとめ

結論、pythonはvscodeから実行できるようなアクセス権限になっていなかったのでエラーになったけど、PYで実行すればpathとか関係なしに最新のversionを使用してpythonファイルを実行してくれるから動いちゃうんだけど、バージョン指定が必要な場合はコマンドがシェバンで指定しないと想定外の動きになっちゃうかもしれないよ。

ということでした。
なるほど勉強になるなぁ。

参考
https://gammasoft.jp/blog/find-out-python-launcher/
https://gammasoft.jp/python/python-version-management/