いいから黙ってこの記事通りにPython環境を立てろ(mac編)

# 注意事項
- 各自のマシンの環境破壊および構築は各自の責任で。
- 環境破壊を行う前に、 `pip freeze > requirements.txt` などにより自身が利用しているパッケージリストを保持することをお勧めする。
- シェルコマンドの `%` はコマンドであることを示しているだけなので、実際の入力では不要。

# Part 1: 過去の清算編

## [必須] シェルの読み込み設定をすべて削除する
bashを使っている場合は `~/.bash_profile` および `~/.bashrc` を、zshの場合は `~/.zsh_profile` および `~/.zshrc` を確認し、Pythonに関するコマンドは全て削除する。特に、Anacondaを入れたことがある場合はかなり汚くなっているはず。
(元々ファイルがない場合はなくてOK)

### 例: Anacondaが勝手に追記するコード
一例 [参考](https://atsushinotes.com/uninstall-anaconda-from-mac/)

```shell:.bash_profile/.zshrc
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/hoge/opt/anaconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/Users/hoge/opt/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/Users/hoge/opt/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/Users/hoge/opt/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<
```

## 公式サイト(python.org)からダウンロードした記憶がある
※間違えてmacOS標準のPython(2.7)をアンインストールする可能性があるので、十分に気をつけること。

https://code-graffiti.com/how-to-uninstall-official-python3-on-mac/

### 本体とフレームワークの削除

```shell:Bash/Zsh
% sudo rm -rf /usr/local/bin/python3
% sudo rm -rf /Library/Frameworks/Python.framework
```

### シンボリックリンクの削除

```shell:Bash/Zsh
% ls -l /usr/local/bin | grep Python
```

→表示される **Python3系の** シンボリックリンクを削除する。不安であればFinderで消す。
(隠しフォルダの表示設定を忘れずに)

## Anacondaをインストールした記憶がある
大学の授業などで「とりあえずAnaconda入れておけばいいから！」っていうやつ、ほんまに……

https://weblabo.oscasierra.net/python-anaconda-uninstall-macos/

https://qiita.com/yu_ku/items/efe0513f1b8036c2d2f8

※pyenv経由でAnacondaやminicondaを導入した場合は後述するpyenvの項を参照。

方法は大体共通。

### Anaconda Cleanする

```shell:Bash/Zsh
% conda install anaconda-clean
% anaconda-clean
# 1つずつ確認入力が必要なので、すべて y と打っておけばOK
% rm -rf ~/.anaconda_backup
```

### 本体のディレクトリを確認する

```shell:Bash/Zsh
% env | grep CONDA
```

ここで表示されるディレクトリ(ここでは `/anaconda3` であったとする)を丸ごと削除する。

```shell:Bash/Zsh
% sudo rm -rf /anaconda3
```

最後に、 `/Applications`ディレクトリに `Anaconda-Navigator.app` が残っている場合はこれも削除する。

## HomerbrewのPythonをそのまま使っている
下手に削除すると**依存パッケージが死ぬのでそのままにしておく**。`~/.bash_profile` や `~/.zshrc`を清算済であればさほど問題はないはず。

## pyenv経由でインストールしている
過去を清算しよう。

### 現在インストール済のバージョンを確認する

```shell:Bash/Zsh
% pyenv versions
```

### 一旦全部削除

`system`**以外を**すべて一旦消す。「バージョン名」とは `pyenv versions` でリストされる項目の値そのまま。

```shell:Bash/Zsh
% pyenv uninstall バージョン名
```

ちなみに `system` を消したら……自分で解決法を探して。

## 最終確認
この時点で、ターミナルからPythonを呼び出す時のバージョンを確認する。

```shell:Bash/Zsh
% python -V
Python 2.7.18
```

Python2系が表示されている場合は、macOS標準のPythonが呼び出されているのでOK。次に進む。
引き続き3系が表示される場合は、その他のPython 3がどこかに潜んでいるので、環境変数などから炙り出して削除を試みる。

# Part 2: 環境構築編
## Homebrewのインストール
入れたことがない方はこれを入れておく。プログラミングを本格的に勉強する場合は、macに各種パッケージを導入するために必須のシステムになる。

https://brew.sh/index_ja


```shell:Bash/Zsh
% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

## pyenvのインストール

```shell:Bash/Zsh
% brew install pyenv
```

pyenvじゃない何かをインストールし始めることがあるが、Homebrewはよく「なにかのパッケージをインストールする際に、Homebrew自身やインストール済パッケージの更新を行う」仕様になっているので、よくある事象としてスルーする。

## シェルの設定を確認する
`~/.bash_profile` や　`~/.zshrc` などに、以下のコードが追加されていることを確認する。なければ記述しておく。
また、似たようなコードが書かれていたけどなんかうまく動かない！という場合は、以下のコードに書き換えるとうまくいくかもしれない。

```shell:.bash_profile/.zshrc
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
```

## 必要なバージョンのインストール
pyenvのインストールでの手順は以下の通り。

### インストール可能なバージョンを指定

```shell:Bash/Zsh
% pyenv install --list
```

一覧が多すぎる……という場合は、以下のようにすると絞り込みが可能。

```shell:Bash/Zsh
% pyenv install --list | grep 3.11
  3.11.0
  3.11-dev
  3.11.1
  miniconda3-4.3.11
```

### インストールする

```Shell:Bash/Zsh
% pyenv install 3.10.5
```

### マシン全体でそのバージョンを有効にする

```shell:Bash/Zsh
% pyenv global 3.10.5
```

### 現在のディレクトリ以下で特定のバージョンを有効化する

```shell:Bash/Zsh
% pyenv local 3.8.2
```

### 適用されているバージョンを確認する

```shell:Bash/Zsh
% python -V
3.9.11
```

このときに `2.7.18` が出てきて、 `python3 -V` にするとうまくいく場合は、以下のコマンドで現在利用されているバージョンを確認すること。

```shell:Bash/Zsh
% pyenv versions                  
  system
* 3.9.11 (set by /Users/hoge/.pyenv/version)
  3.10.5
```



## バージョンの選び方

2023年1月7日現在、pyenv最新のPythonの安定版は3.11.1である。Pythonは3系の間ではおおむね後方互換性が維持されており、最近のアップデートで初心者が使う機能に致命的な変更は行われていない。よって、特にこだわりがなければ最新版を入れておけば問題ないだろう。

AtCoderの動作テストを意識する場合は、以下のようにすると良い。

```shell:Bash/Zsh
% pyenv install 3.8.2
% pyenv install pypy3.7-7.3.0
% pyenv local 3.8.2 pypy3.7-7.3.0
```

Google Colabや大学の講義で用意されたコードを実行する場合、ここ数年以内に書かれたコードであれば、3.8以上であれば問題ないと思われる。ただし、requirementsなどで指定されているライブラリが最新のバージョンに対応していなかったり、逆に古いバージョンでは動かなかったりすることがあるので、他人のコードを流用する環境では必ずバージョンを確認すること。

# Part3: 仮想環境をvenvで作成する
Pythonの仮想環境構築にはいくつかの方法があるが、ここではvenvを用いた手法を紹介する。
venvは pure Python に含まれているので、外部ライブラリのインストールは不要。

## 基本的な使い方

参考

https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e

### 仮想環境をディレクトリに作成する

```shell:Bash/Zsh
% python -m venv 環境の名前
```

### 有効化する

```shell:Bash/Zsh
% source 環境の名前/bin/activate
# または
% . 環境の名前/bin/activate
```

### 無効化する
% deactivate

## おまけ：venv改造版
以下の点を改造しており、既存のvenvの関数がオーバーライドされます。 `.bash_profile` や `.zshrc` に書き込んでください。

- activate/deactivate だけで仮想環境を出入りできる(deactivateはどこのディレクトリにいてもOK)
- 仮想環境作成時に自動的にpip, setuptoolsをアップグレードする他、一部のライブラリインストールで便利なwheelをインストール
- 同階層にrequirements.txtがあれば、そこに書かれたライブラリをインストールする

```shell:.bash_profile/.zshrc
############################
# venvのオーバーライド
############################

function deactivate () {
    # reset old environment variables
    if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
        PATH="${_OLD_VIRTUAL_PATH:-}"
        export PATH
        unset _OLD_VIRTUAL_PATH
    fi
    if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
        PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
        export PYTHONHOME
        unset _OLD_VIRTUAL_PYTHONHOME
    fi

    # This should detect bash and zsh, which have a hash command that must
    # be called to get it to forget past commands.  Without forgetting
    # past commands the $PATH changes we made may not be respected
    if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
        hash -r 2> /dev/null
    fi

    if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
        PS1="${_OLD_VIRTUAL_PS1:-}"
        export PS1
        unset _OLD_VIRTUAL_PS1
    fi

    unset VIRTUAL_ENV
    _VENV_MODE=false
    # 不要
    # if [ ! "${1:-}" = "nondestructive" ] ; then
    # # Self destruct!
    #     unset -f deactivate
    # fi
}

function activate_venv () {
    # 今入っている仮想環境があれば出る
    if $_VENV_MODE; then
      deactivate
    fi
    # カレントディレクトリ直下にあるvenvを利用する
    VIRTUAL_ENV="$PWD/.venv"
    export VIRTUAL_ENV

    _OLD_VIRTUAL_PATH="$PATH"
    PATH="$VIRTUAL_ENV/bin:$PATH"
    export PATH

    # unset PYTHONHOME if set
    # this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
    # could use `if (set -u; : $PYTHONHOME) ;` in bash
    if [ -n "${PYTHONHOME:-}" ] ; then
        _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
        unset PYTHONHOME
    fi

    if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
        _OLD_VIRTUAL_PS1="${PS1:-}"
        # ここは起動したディレクトリの名前に変更する
        PS1="%B%F{yellow}($(basename $PWD))%b%f ${PS1:-}"
        export PS1
    fi

    # This should detect bash and zsh, which have a hash command that must
    # be called to get it to forget past commands.  Without forgetting
    # past commands the $PATH changes we made may not be respected
    if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
        hash -r 2> /dev/null
    fi

    _VENV_MODE=true
}
function activate () {
	if [ ! -e .venv/bin/activate ]; then
        # 新たに仮想環境を作成
		python -m venv .venv
        activate_venv
		echo "environments has been constructed"
        # pipのアップグレード
		pip install -U pip
		pip install -U setuptools
        pip install wheel
        echo "pip in venv has been updated to latest version"
		# ディレクトリ直下のrequirementsを読み込んでパッケージをインストール
		if [ -e requirements.txt ]; then
			pip install -r requirements.txt
			echo "libraries has been installed from requirements"
		fi
  else
      activate_venv
  fi
}

# venvからdeactivateしたときに元のPS1に戻せるようにする
# これはgit-promptとvenvを併用した時にプロンプトの表示がおかしくなるため
export _OLD_VIRTUAL_PS1=$PS1
export _VENV_MODE=false
```

# おわり

Windows編？作りません。