pythonの仮想化環境についてのまとめ
仮想化とは何か?
特定のプロジェクトや特定のディレクトリに限定したpythonの環境をつくることを仮想化という。 またpythonの環境には大きく分けて2つある。 一つはpython本体で、python2.7とかpython3.6とか、どのversionのpythonを使うかということ。 もう一つは、packageで、どこのディレクトリのpackageを使うかということ。
要するに仮想化をするとは、 特定のプロジェクト(ディレクトリ)で どのpython本体とどのpackageディレクトリを使うかを決めるだけの話。
どのプログラムを使うかというのは、 要するに実行するときのPATHを決めるというだけの話である。 だから仮想化を理解するにはPATHのことを理解する必要がある。
仮想化ではPATHが一番大事(たぶん)
そもそもPATHとは環境変数の一つである。 環境変数とは、OSの機能で、タスクが動作するのに必要な情報を書き込む仕組みである。 macではターミナルでprintenvとコマンドを打てば設定されている環境変数が表示される。
TERM_PROGRAM=Apple_Terminal SHELL=/bin/bash USER=kapi SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.t748VX0p9g/Listeners PATH=/usr/local/opt/llvm/bin:/Users/kapi/.pyenv/shims:/Users/kapi/.pyenv/shims:/Users/kapi/.pyenv/bin:/Applications/MacVim.app/Contents/MacOS:/usr/local/bin:/Users/kapi/.nvm/versions/node/v9.3.0/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/Applications/Wireshark.app/Contents/MacOS:Users/kapi/.local/bin HOME=/Users/kapi ...
USERやSHELLなどが設定されているのがわかる。 で、PATHとは環境変数の一つであり、コマンドがある場所を列挙した変数のことである。
ターミナルでlsコマンドを打つとファイルが表示されるのはlsという実行ファイルを見つけて実行しているからだが、 もしPATH情報がないと、実行ファイルがどこにあるかを全ファイルから探す必要があり、めちゃくちゃ時間がかかってしまう。 もしくは、lsと打つのではなく、/bin/ls のように実行ファイルがある場所を毎回指定する必要がある(フルパスという)
PATHがあれば、PATHの場所だけコマンドを探せばいい。 また実行ファイルはPATHのあるところに置くか、実行ファイルの場所をPATHに追加したらよい。
なお、PATHだけを表示させるには echo $PATH でよく、 PATHは .bashrc または .bash_profile に記載されている。
複数の実行ファイルがあるときの挙動
そして、ここが仮想化で重要なところだが、 例えばpythonインタプリタの実行ファイルが複数あるとき、どれが実行されるのか? それはPATHが書かれている順番に探していって、先に見つかった方である。 PATHにpython2.7のpathが書かれていればpython2.7インタプリタが実行される。 と、いうことはPATHにかかれている順番をコントロールしたら、任意のpythonを実行できるのか? YES. pyenvではまさにそれをしている。
参考 [Mac]環境変数PATHの設定・変更・追加・確認・順番入れ替えの方法 | Gabekore Garage
pyenvのお仕事
pyenvの大きな仕事は2点
pyenvがやらないこと
基本的にコマンドを先回りするので特にactivateなどは必要ない。 ディレクトリに設定ファイルを置いてそれを先回りして読むことをしている。 詳しくはgitをみるべし。 pyenv/pyenv: Simple Python version management
pythonインタプリタのインストール
pyenv install -list でインストール可能なリストを表示できる。 pyenvを最新にしておかないとだめだった気がする。 (pyenv update や pyenvのルートディレクトリで git pullする) anacondaなんかもインストール可能
ディレクトリごとにpythonの環境を分ける
pyenv local 環境名 とすると、そのディレクトリに .python-version が作られ、そこに環境名が書かれている。 で、このディレクトリでpython関係のコマンドを打つと、その環境のものが使われる。 例えばpipをしたら、.python-versionのところにだけインストールされる。 pyenv versions としたら、どのversionがインストールされていて、そのディレクトリではどのversionを使うかが示される また、どこの.python-versionファイルによって設定されたかも表示される
MacBook-Pro:tmp kapi$ pyenv versions system 2.7.16 3.6.9 3.7.4 * anaconda3-5.3.1 (set by /Users/kapi/Documents/GitHub/anaconda3-5.3.1/.python-version)
localでの設定がなければ、ディレクトリをさかのぼり、pyenvのrootにいく。 rootではgloalの設定がある。 それもなければ、systemのpythonを使うことになる。
なお実際にpyenvでやっていることは pyenv、pyenv-virtualenv、venv、Anaconda、Pipenv。私はPipenvを使う。 - Qiita から
- $PATHの先頭にPYENV/shimsを挿入し、あらゆるPython系コマンドへのアクセスに割り込む。
- いま動かすべきPythonインタプリタを探す。
- 受け取ったコマンド(例えばpython main.py、pip3 install -r)を、その探したインタプリタに投げる。 すなわち、諸々のコマンドを適切な窓口に振り分ける、受付係を引き受けてくれるのである。 適切なインタプリタを探すために、pyenvは以下の操作を行う:
- もし環境変数PYTHON_VERSIONが設定されていれば、そのバージョンに従う。
- そうでなければ、今のディレクトリから順に親ディレクトリを遡っていく。その途中で.python_versionファイルが見つかれば、そこに書かれてい>るバージョンに従う。
- ルートまで遡っても見つからなければ、グローバルに設定されているバージョンに従う。 そういうわけで、which pythonをしても、pyenvの管理化では、 /Users/kapi/.pyenv/shims/python がどこも表示される
pyenvはpythonインタプリタとpackageは分けることは出来ない
インタプリタとpackageがセットになっていると考えていい。 pipをしたら.python-versionで設定されているところにインストールされるだけである。 だから、python3.7.4で2つのパッケージ環境を作ることはできない。 同じpythonインタプリタでパッケージ環境を分けるにはvenvをつかう必要がある。
venvのお仕事
venvがやるのはパッケージ環境の仮想化である。 環境を作ると、そのディレクトリ下に仮想環境の実行ファイルがおかれ、 どのパッケージのディレクトリを使うか、のpathを決めている。
ただし、pyenvと違ってコマンドを乗っ取るわけではないので、
仮想環境を使うには activateが必要になる。
source [環境作ったディレクトリ]/bin/activate
でactivateする。(deactivate としたらdeactivateされる)
activateした状態でpipすると、指定されたほうのsite-packagesにinstallされる
ちなみにvenvは公式あまりわかりやすくなかった venv --- 仮想環境の作成 — Python 3.7.4 ドキュメント こっちのqiitaの方がわかりやすかった venv: Python 仮想環境管理 - Qiita
venvのやっていることを確認するにはpythonインタプリタを起動してsite-packagesのパスを確認したらいい。
これは、venvでない、環境でのpythonのimportのpath
MacBook-Pro:~ kapi$ python Python 3.7.4 (default, Aug 14 2019, 08:40:34) [Clang 10.0.1 (clang-1001.0.46.4)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> import pprint >>> pprint.pprint(sys.path) ['', '/Users/kapi/.pyenv/versions/3.7.4/lib/python37.zip', '/Users/kapi/.pyenv/versions/3.7.4/lib/python3.7', '/Users/kapi/.pyenv/versions/3.7.4/lib/python3.7/lib-dynload', '/Users/kapi/.pyenv/versions/3.7.4/lib/python3.7/site-packages'] >>>
こっちは、python -m venv try_venv で作った環境をactivateして作った環境でのpythonのimportのpath
(try_venv) MacBook-Pro:~ kapi$ python Python 3.7.4 (default, Aug 14 2019, 08:40:34) [Clang 10.0.1 (clang-1001.0.46.4)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import sys >>> import pprint >>> pprint.pprint(sys.path) ['', '/Users/kapi/.pyenv/versions/3.7.4/lib/python37.zip', '/Users/kapi/.pyenv/versions/3.7.4/lib/python3.7', '/Users/kapi/.pyenv/versions/3.7.4/lib/python3.7/lib-dynload', '/Users/kapi/Documents/GitHub/try/try_venv/lib/python3.7/site-packages'] >>>
見て分かる通り、python本体は共通で、site-packagesだけが異なる。 これがvenvがやっていること。 (try_venv)という環境でpipをすると、こっちにだけ、installされることになる。なるほど〜〜。
pipenvについて
これはちょっとわかりにくい より抽象化されている。 ディレクトリごとの環境が基本みたいだ。 またpythonはおそらく共通で使っているということだな。 で、activateするんじゃなくて、 pipenvコマンドをつかってinstallやら実行やらをすると。 多分、そのディレクトリにパッケージのパスがかいてあって、それを探してそう。 また使うときに調べよう。
で、どう使うか?
よく考えたら別にvenvも使わなかった。。。
アプリ開発するわけでもない
とはいえ、環境を明示的にしておいた方がいいのも確かなので、
cvの勉強用にはpyenvでanacondaをいれておく。
具体的にはpyenvでanacondaをインストールして、
特定のフォルダ以下で
pyenv local anacondaxxx
としておいた。
bashを使いやすくする
とても参考になった記事
- 主に下記記事を参考にショートカットキーを覚える
- ショートカットの元の語源はこの記事がちゃんと書いてくれている
- コマンドの履歴を使うことに関しては下の記事が役に立った
また設定変更としては以下を行った
Docker, VSCode, pytest, GitHubについて最近みた資料
あとで個別には軽くまとめるつもり。つもり。
- Dockerの入門
- Linuxに関すること
- VSCodeの入門
- pytestの入門
- import errorについて
- 実行している場所は適切か?
- Pythonで「ImportError: No module named …」が出た時の3つの対処法
- import errorについて
- GitHubの入門
- VSCode + Docker で Python開発環境
- Macの操作
- スクレイピング
- Linuxに関すること
- VSCodeの入門
- pytestの入門
- import errorについて
- 実行している場所は適切か?
- Pythonで「ImportError: No module named …」が出た時の3つの対処法
- import errorについて
- GitHubの入門
- VSCode + Docker で Python開発環境
- Macの操作
- スクレイピング
- PythonとBeautiful Soupでスクレイピング - Qiita
- BeautifulSoup+Requestsの基本
- Python Webスクレイピング テクニック集「取得できない値は無い」JavaScript対応@追記あり6/12 - Qiita
- PythonでWebページ内の特定のタグ要素をまとめて取得する
- Beautifulsoup でWebページのリンクを抽出する - Qiita
- PythonとBeautiful Soupでスクレイピング - Qiita
- 入門系記事にはない、実践/現場のPythonスクレイピング流儀【2019年最新】 - Qiita
- PythonでCSVファイルを読み込み・書き込み(入力・出力) | note.nkmk.me
筋トレと学びを支える要素
これ、めちゃくちゃおもしろい。 筋トレ初めて1年後の生存率は3.7% !!!
意外なのは指数関数的に減っているところ。 半年継続できた人の生存率はもっと高いかと思ってた。 多少はマシなくらいで、半年継続してもじゃんじゃか脱落する。
スポーツジムでの筋トレ継続率(Sperandei S, J Sci Med Sport, 2016)。これは、激しくワロタ。集団行動が強制される学校とか会社とかがいかに重要か、というグラフや。 https://t.co/QXdt48livv pic.twitter.com/GhcPZBYJxP
— Kazuki Fujisawa (@kazu_fujisawa) July 6, 2019
結局のところ、短期的には困らないが長期的には利益になるような退屈な作業を、”自分の意志”だけで続けることはまず無理、ということがよくよくわかる。
私も社会人になってから何度も英語学習で挫折したのだけど、短期的に退屈な作業を自分の意志だけに頼っていたので、もう最初から負けは確定していたのだな。
ではどうしたらいいのか? 数学ガールで有名な結城先生が相変わらずいいこと書いてくれている。
学びを支える要素(学ぶときの心がけ) https://mm.hyuki.net/n/n57686f374b39
- 時間を掛ける
- 成功を体験する
- 孤独を避ける
学校や会社では基本この3つは満たされやすい。 時間は強制的に掛けられるし、結果に対する評価も定期的にしてくれるし、集団の圧力があり孤独でない。
社会人などになって集団に属していない人にとってはこの3つの要素を確保できる環境を作ることこそが大事で、意志なんかに頼っても無駄である。
あと、phaさんの知の整理術という本では、勉強をする際に次の3つが大事だと書いてる。
- 「習慣の力」でやる
- 「ゲーム感覚」でやる
- 「楽しいことだけ」やる
こちらはphaさんらしく、いかにストレスをなくして続けるか、ということに重点がおかれている。
たくさん失敗して自分にとって大切だなと思うのは、性急にわかりやすい結果だけを求めず、作業自体を楽しくできるようにすること。
筋トレだったら見た目であったり、ブログだったら閲覧数だったりがわかりやすい結果である。 わかりやすい結果はわかりやすいから注目しやすいのだけど、必ずしも作業量とリアルタイムに相関するわけではない。なので結果がでないとやる気がなくなって、作業量も減っていき、ますます結果がでなくなるみたいなことにもなりがちだ。
次に自分が大切だと思うのは結城先生の孤独を避ける、ということだ。これは喜びを分かち合えたり、わからないことを聞けたりということもあるし、同調圧力みたいなものもある。
ついついここは自分は軽視してしまって、そんなのなくても一人でできるわ!みたいに思ってたけど全然できなかった。やっぱり集団の力は偉大である。
如何に楽しくやるか、如何に他人と絡むか、を重視して筋トレやら勉強はやっていこうと思う。
Dockerを使う
DockerでPythonの機械学習環境を作る。 以下の記事を参考にする。
$ docker run -p 8888:8888 --name ml-container -it asashiho/ml-jupyter-python3
dockerを起動してこのコマンドを打つだけ。 超簡単! これはすごい。 環境構築がめちゃくちゃ楽。
終了はcontrol + C と。
ん、再開はどうしたらいいのか? 一旦閉じると、
http://localhost:8888/?token=<your token>
では当然もうアクセスできない。
$ docker run -p 8888:8888 --name ml-container -it asashiho/ml-jupyter-python3
を再度打つと、error
Error response from daemon: Conflict. The container name "/ml-container" is already in use by container "75a667c2f32b7043e763fdf464d1cc35555f6703e983fd0c8aa99110066468cd". You have to remove (or rename) that container to be able to reuse that name.
コンテナを確認
docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 75a667c2f32b asashiho/ml-jupyter-python3 "jupyter notebook --…" 3 hours ago Exited (0) 3 hours ago ml-container fb20782c9075 hello-world "/hello" 4 hours ago Exited (0) 4 hours ago eager_dhawan
これでみると、たしかにいる。
で、restartしてから、再度localhostにアクセスしたらできた。 またnotebookも残っていた。
docker container restart 75a667c2f32b
コマンドはこれ参考にした
他にも参考になりそうな記事
まずはこれ
docs.docker.jp
kaggleのkarnelのDocker
amalog.hateblo.jp
Docker for Mac を uninstall
PC移行してDockerを起動しようとしたら以下のエラー
docker com.docker.osx.hyperkit.linux failed to start Exit code 1
直し方わからず。。残念なことに入れ直す。 通常のDockerのmenuに入れないので、手動で消す。 以下の記事を参考にした。 nektony.com
で、あとは普通にmac用のDockerをダウンロードしていれた。
macOS Mojave でpyenv install 3.4.3 が失敗したときの対応
pyenvでのpythonのinstallが失敗したときの対応を記録しておく。
rMBP01:~ kapi$ pyenv install 3.4.3 python-build: use openssl from homebrew python-build: use readline from homebrew Downloading Python-3.4.3.tar.xz... -> https://www.python.org/ftp/python/3.4.3/Python-3.4.3.tar.xz Installing Python-3.4.3... python-build: use readline from homebrew BUILD FAILED (OS X 10.14.4 using python-build 20180424) Inspect or clean up the working tree at /var/folders/dj/1y_c81qj4jx9mv7zzv8zmh240000gn/T/python-build.20190509123945.6287 Results logged to /var/folders/dj/1y_c81qj4jx9mv7zzv8zmh240000gn/T/python-build.20190509123945.6287.log Last 10 log lines: checking for --without-gcc... no checking for gcc... clang checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... configure: error: in `/var/folders/dj/1y_c81qj4jx9mv7zzv8zmh240000gn/T/python-build.20190509123945.6287/Python-3.4.3': configure: error: cannot run C compiled programs. If you meant to cross compile, use `--host'. See `config.log' for more details make: *** No targets specified and no makefile found. Stop.
config.logを調べる
$cd /var/folders/dj/1y_c81qj4jx9mv7zzv8zmh240000gn/T/python-build.20190509123945.6287/Python-3.4.3 $cat config.log ~~~~~~~ configure:3926: clang -V >&5 clang-4.0: error: argument to '-V' is missing (expected 1 value) clang-4.0: error: no input files configure:3937: $? = 1 configure:3926: clang -qversion >&5 clang-4.0: error: unknown argument: '-qversion' clang-4.0: error: no input files ~~~~~~~ configure:4105: clang -o conftest -I/usr/local/opt/readline/include -I/usr/local/opt/readline/include -I/usr/local/opt/openssl/include -I/Users/prokapi/.pyenv/versions/3.4.3/include -L/usr/local/opt/readline/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/openssl/lib -L/Users/prokapi/.pyenv/versions/3.4.3/lib conftest.c >&5 conftest.c:8:10: fatal error: 'stdio.h' file not found #include <stdio.h> ^~~~~~~~~ 1 error generated.
clangのところでerrorが発生している。 macに入っているclangを調べる。
https://teratail.com/questions/176364
which -a clang /usr/local/opt/llvm/bin/clang /usr/bin/clang
上のclangが使われていて、それだとビルドが失敗してる? /usr/bin/clang の方はx-codeのclang。本来はこっちが使われるべきでは。 上のclangは使っていないので削除することにする。
$ brew uninstall llvm Uninstalling /usr/local/Cellar/llvm/4.0.0... (2,245 files, 1GB)
再びpyenvでinstallする。
pyenv install 2.7.1
ERROR: The Python zlib extension was not compiled. Missing the zlib? Please consult to the Wiki page to fix the problem. https://github.com/yyuu/pyenv/wiki/Common-build-problems BUILD FAILED
今度は違うエラー。対処方法はここにあった。
https://qiita.com/TEWi_R/items/aac5bada7c17dba1a7f0
$ CFLAGS="-I$(xcrun --show-sdk-path)/usr/include" pyenv install -v 2.7.1
ようやくpython 2.7.1のビルドができた。 3系も試してみる。
$ pyenv install 3.4.1
zipimport.ZipImportError: can't decompress data; zlib not available make: *** [install] Error 1
このエラーも対策があった。ありがとう。
https://qiita.com/zreactor/items/c3fd04417e0d61af0afe
xcode-selectの最新バージョン(2354)にMojave用のmacOS SDK headerがデフォルトで入っていないのが原因のようです。
マニュアルで以下をインストールする必要ある:
sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
できました!
$ pyenv install 3.4.1
これで完了。