Pythonパッケージ作りの初歩の初歩 その2

fijixfiji.hatenablog.com
前回(上のページ)に続いて、今回も、ライトなPythonユーザーがパッケージについていろいろ調べながら理解したことをまとめていきたいと思います。

今回のテーマは、setup.pyのsetupです。

主に読んだところはここ:

pipを使っていて、いくつかの疑問がありました。
例えば、pip install pillowでインストールした場合、実際にimportする場合は、from PIL import Imageといった感じで、pillowではなく、PILと指定したりします。pip installする時の名前と、importする時の名前が異なるパッケージがたまにある(scikit-learnならsklearnとか *1 )ので、なんでだろうというものです。
あと、自分でsetup.pyを書いた時に、py_modulespakagespackage_dirと、importする時の名前がごっちゃになって、わかんないよーとなりました。

基本の「き」

配布物のパッケージを作るには、まず、作業するようのディレクトリを用意します。そしてその中に配布したいものと一緒にsetup.pyというファイルを用意します。

<root>/
        setup.py
        《その他いろいろなファイル》

setup.py

from setuptools import setup

setup(name='hoge',
     version='1.0', 
...略...

という感じになります。その他いろいろなファイルには、配布したい(モジュールコンテナとしての)パッケージや、パッケージ、拡張モジュール用のソースコード、データから、READEMEファイル、ライセンスのファイルなどなどを含めることができます。だいたい、必要なものは、決まっているので、(インターン向けに書いた)Pythonパッケージを作る方法 - Qiita(や GitHub - kennethreitz/samplemod: Sample module for Python-Guide.org.)を参考にするとだいたい間違わないと思います。

setup.pyの引数たち

setupの引数を全てではないですが、いろいろと見ていきます。Building and Distributing Packages with Setuptools — setuptools 38.5.1 documentation

まずは、nameについて。
nameは、sampleproject/setup.py at master · pypa/sampleproject · GitHubの説明からいくと、"the name of your project"です。プロジェクトの名前。または、下記の引用にあるように、「配布物の名前」です。ここに記述してある名前が、pip installの時に指定できます。あと、インストールしたあとに、pip listしたときに表示される名前になります。後述しますが、ここのnameはimportのときに使う文字とは(習わしでは一致しますが、基本的には)関係がありません。

配布物の名前は name オプションで個々に指定し、配布されるモジュールの一つと配布物を同じ名前にする必要はないことに注意してください (とはいえ、この命名方法はよいならわしでしょう)。ただし、配布物名はファイル名を作成するときに使われるので、文字、数字、アンダースコア、ハイフンだけで構成しなければなりません。

https://docs.python.jp/3/distutils/examples.html#pure-python-distribution-by-module


次に、versionについて。
「バージョン番号は major.minor[.patch[.sub]] の形式をとるよう奨めます。」(2. setup スクリプトを書く — Python 3.6.4 ドキュメント)のように書きます。PEP 440(PEP 440 -- Version Identification and Dependency Specification | Python.org)もあるようなので、参照ください。

descriptionurl author author_emailなどなどを記述して行きます。
https://docs.python.jp/3/distutils/setupscript.html#additional-meta-datahttps://github.com/pypa/sampleproject/blob/master/setup.pyが参考になると思います。
どんなキーがあるかというと、Building and Distributing Packages with Setuptools — setuptools 38.5.1 documentationに一覧があります(多分公式のドキュメントがこれかな、きっと)。


で、続いて、本題のpy_modulespackagespackage_dirの3つについてです。
setup.pyの中でのモジュールやパッケージの指定方法についてですが、https://docs.python.jp/3/distutils/examples.htmlがかなりわかりやすいです。で、若干、つまずいたところとしては、利用する(importするとき)の記述とどういう関係になるのかという点でした。import mypkgみたいなことをしたときに、どう指定するかという利用する側からの補足を入れてみたいと思います。

まず、7.1のモジュール形式という形です。(配布物としての)パッケージだけど、配布するものが(モジュールコンテナとしての)パッケージじゃなくモジュールのパターンです。
ディレクトリ構成:setup.pyと同じところにfooモジュールとbarモジュールが置いてある。

<root>/
        setup.py
        foo.py
        bar.py

setup.py:

setup(name='foobarpkg',
      version='1.0',
      py_modules=['foo', 'bar'],
      )

foo.py:fooモジュール

def foo():
    print('foooo!')

こういう状態で、インストールを行うと、pip listの中には、foobarpkgが現れます。利用するときは、"モジュール"がインストールされているので、

import foo
foo.for()

のように利用します。個人的にはちょっと驚いたところでした。一切にnamefoobarpkgが登場しません。fooモジュールとbarモジュールが、(配布物としてのパッケージの名前と関係なく)グローバルな名前で入ってしまいました。


続いて、「典型的なケース」です。(モジュールコンテナとしての)パッケージを配布する(配布物としての)パッケージを作るときです。
ディレクトリ構成:foobarディレクトリに、foobarパッケージ(fooモジュールとbarモジュール)がある。

<root>/
        setup.py
        foobar/
                 __init__.py
                 foo.py
                 bar.py

setup.py:

setup(name='foobarpkg',
      version='1.0',
      packages=['foobar'],
      )

foo.py:foobar/fooモジュール

def foo():
    print('foooo!')

pakagesで指定したので、foobarディレクトリをfoobarパッケージとしてインストールしてあります。構造的には、foobarパッケージの中にfooモジュールがあるので、使うときは、

from foobar import foo
foo.foo()

または

import foobar.foo
foobar.foo.foo()

みたいに記述します。で、ここでもnameで指定したfoobarpkgは登場しません。

このようにsetup.pyのpy_modulespakagesでパッケージかモジュールを羅列していけば、パッケージかモジュールを配布するパッケージを作成することができます。


で、だいたい原則がわかったので、いろいろ応用させることができます。foobarpkgパッケージ1つで、foobarパッケージとfooパッケージとbarパッケージの3つを配布することにしようと思うと、

<root>/
        setup.py
        foobar/
                 __init__.py
                 foo.py
                 bar.py
        foo/
                 __init__.py
                 foofoo.py
        bar/
                 __init__.py
                 barbar.py

setup.py:

from distutils.core import setup
setup(name='foobarpkg',
      version='1.0',
      packages=['foobar', 'foo', 'bar'],
      )

のようにすればよく、利用するときは、

from foobar import foo
from foo import foofoo
from bar import barbar

のように指定します。


2つ前の例で、「foobarディレクトリをfoobarパッケージとしてインストール」と書きましたが、packagesに書く文字列は、配布した際に使って欲しい(importで指定して欲しい)名前になります。パッケージの中のディレクトリ名とは限らない(デフォルトではそう解釈するみたいです)。
なので、「配布したいパッケージの名前(foobar) <---> foobarpkgパッケージ内でのそのパッケージがあるディレクトリ」(典型的な例では一致)の対応を決めることもできます。それが、pakage_dirになります。package_dirの辞書は、キーがimportするときに使うパッケージ名、値が実際に存在しているディレクトリになります。

ややこしいですが、fooディレクトリのパッケージをbarという名前のパッケージとして、barディレクトリのパッケージをfooディレクトリのパッケージとして配布することもできます(一番簡単な例は、ドキュメントに書いてあるとおり、srcっていうディレクトリの中にあるパッケージに、foobarというパッケージ名をつけられる例だと思います。)

<root>/
        setup.py
        src/
                 __init__.py
                 foo.py
                 bar.py
        foo/
                 __init__.py
                 foofoo.py
        bar/
                 __init__.py
                 barbar.py
from distutils.core import setup
setup(name='foobarpkg',
      version='1.0',
      packages=['foobar', 'foo', 'bar'],
      package_dir={'foobar': 'src', 'foo': 'bar', 'bar': 'foo'}
      )

importするときは、

from bar import foofoo
foofoo.foo()

のようになります。

が、こんな無駄な対応はしないほうが良いと思います。(あと、別件ですが、pip install -e ./foobarpkgって、別にpackage_dirを読んでくるわけじゃないの??ここは謎いが深まった・・・)

ドキュメントの例にあるルートディレクトリにパッケージの名前をつけたりするやつとかも、もう理解できるようになりました。


で、ちょっと脇道へ。
上記のようにパッケージした場合、関数を一つ呼び出すのに、import foobarしたあとにfoobar.foo.foo()のようにモジュールを書くか、from foobar import fooしたあとにfoo.foo()しなきゃいけなく、特に小さなパッケージの場合は、めんどくさいです。(つまり、モジュールみたいな感じで使いたいけど、パッケージなんですけどという状況)。その場合は、__init__.pyに一工夫加えると、import foobarしたあとに、foobar.foo()のように呼び出せます。
__init__.py:(fooモジュールからfoo関数をインポートする)

from .foo import foo

です(多分)。このへんは、6. モジュール (module) — Python 3.6.4 ドキュメントとかを読むと、良いかもしれません。

もしも __all__ が定義されていなければ、実行文 from sound.effects import * は、パッケージ sound.effects の全てのサブモジュールを現在の名前空間の中へ import しません 。この文は単に(場合によっては初期化コード __init__.py を実行して) パッケージ sound.effects が import されたということを確認し、そのパッケージで定義されている名前を全て import するだけです。 import される名前には、 __init__.py で定義された名前 (と、明示的にロードされたサブモジュール) が含まれます。パッケージのサブモジュールで、以前の import 文で明示的にロードされたものも含みます。

6. モジュール (module) — Python 3.6.4 ドキュメント


配布したいPythonスクリプトと、配布したパッケージの名前の対応関係がわかりましたが、他のも拡張モジュールとして配布する場合があると思います。
拡張モジュールは、プログラミング言語Pythonしか書けないライトなユーザー(僕)の場合、あまり縁がないと思っていましたが、Cythonを書くと、拡張モジュールを作ることになるので、簡単な例と参考になるリンクを書いておこうと思います。

Cythonのソースからだけで拡張モジュール作る場合などは簡単なのですが、Cのライブラリを使う場合ではリンクやコンパイルの時のオプションを指定する必要があります。

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

extensions = [
    Extension("primes", ["primes.pyx"],
        include_dirs = [...],
        libraries = [...],
        library_dirs = [...]),
    # Everything but primes.pyx is included here.
    Extension("*", ["*.pyx"],
        include_dirs = [...],
        libraries = [...],
        library_dirs = [...]),
]
setup(
    name = "My hello app",
    ext_modules = cythonize(extensions),
)
http://cython.readthedocs.io/en/latest/src/reference/compilation.html#configuring-the-c-build

のように、書きます。つまり、include_dirslibrarieslibrary_dirsを指定します。
んで、このオプションがなんなのか理解しないといけないのですが、これは、Cのコンパイルとリンクの知識になるので、

あたりを読みつつ、なんとなく把握しました。
ちなみに、はまりポイントとしては、python - Cython compiled C extension: ImportError: dynamic module does not define init function - Stack Overflowにある通り、
第一引数の末尾のモジュール名と、Cythonのソースコードのファイル名を一致させないと、インポートがうまくできませんので注意です。つまり、

Extensiton("foobarpkg.foo", ["foo.pyx"], ....

みたいな感じです。



install_requiresについて。
依存関係を記述します。ここを記述することで、依存するパッケージも勝手にpipさんが一緒にインストールしてくれます。



最後に、scriptsまたはconsole_scriptsです。
flake8などのツールは、flake8コマンドで、シェルから実行できるようになっていたりします。
なので、シェルで動かすようのコマンドも配布することができます。
指定する方法は2つあり、scriptsに書くか、console_scriptsentry_pointsに書くかします。
わかりやすところとしては、Command Line Scripts — Python Packaging Tutorialがあります。



以上、今日は、ここまで。

setup.pyの引数として紹介していましたが、もろもろのパラメータは、
https://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-filesのように、setup.cfgに書くことも可能らしいです(あんまりよくわからん)


次回へ続く(?)

*1:ちなみに、 sklearn 0.0 : Python Package Indexというnameがついたものが存在していた笑

tryしてreturnしたあとのfinallyについて

タイトルがちょっと意味不明なのですが、こういうことです。

問1. 以下のコードで、ansの値は1と2のどちらでしょうか?

def f(a):
    try:
        a = a + 1
        return a
    finally:
        a = a + 1

ans = f(0)
print(ans) # ??

問2. 以下のコードで、ansのlistは、[0, 1]と[0, 1, 2]のどちらでしょうか?

def h(a):
    try:
        a.append(1)
        return a
    finally:
        a.append(2)

ans = h([0])
print(ans) # ??
続きを読む

NEPというもの

PEPじゃなくて、NEP(NumPy Enhancement Proposals *1)というものもあることを先日(誰かのtweetで)知りました。


NumPyにおけるPython2のサポートについて書かれているProposalがあります。

github.com

全然知らなかったのですが、2系の機能追加等のサポートは、2018年いっぱいまでで、2019年の間はバグフィックスなどのリリースのみで、2020年1月1日からは、Python2系のサポートを終了するらしいです。


とはいうものの、Python2を最近めっきり書かなくなったので、個人的には、時代が変わってゆくなぁーという感慨があるくらいで、影響はほとんどないかなと思っています。
NEPというものがあることは、勉強になりました。

VPS作業記録 vimのビルドの巻

かなり前ですが、vim pluginまわり作業内容。 - みんなのふぃじー(はてなブログ版)で、vimプラグイン周りを整理整頓しようとしたら、Lua付きのvimじゃないことが発覚して、自前でのビルドしよう案件の続きをやりたいと思います。

で、さらに、今回は、+luaだけではなく、+python +python3 +terminalを狙っていきたいと思います。

事前準備

vimを入れる場所は、/usr/localにしたいと思います。
Luaは、yumで入れておく。

# yum install lua
# yum install lua-devel
# yum install luajit
# yum install luajit-devel

Pythonに関しては、--enable-sharedをつけて(?)、/usr/local/bin/python2と/usr/local/bin/python3として、インストールしておく。

オプション

gitでvimをcloneして、vim/srcに移動。

git clone https://github.com/vim/vim.git
cd vim/src 
./configure ここのオプションをどうするか
make
make install
オプション 意味
--enable-fail-if-missing 何か足りなければ、止まってくれる。これつけたまま、configureが通るまで頑張る
--with-features=huge よくわからないけど、いっぱい入れておけということで、huge
--prefix=/usr/local ゆにっくしゅ しぇあー ろーかりゅ
--enable-multibyte 今度調べる
--enable-luainterp lua付きのオプション
--with-luajit jitは早いらしい?
--enable-pythoninterp これで+python
--enable-python3interp これで+python3
--enable-rubyinterp なんとなくつけておく
--enable-terminal :terminalを使えるようにする。
結果
Huge 版 with GTK2 GUI.  機能の一覧 有効(+)/無効(-)
+acl             +file_in_path    +mouse_sgr       +tag_old_static
+arabic          +find_in_path    -mouse_sysmouse  -tag_any_white
+autocmd         +float           +mouse_urxvt     -tcl
+balloon_eval    +folding         +mouse_xterm     +termguicolors
+browse          -footer          +multi_byte      +terminal
++builtin_terms  +fork()          +multi_lang      +terminfo
+byte_offset     +gettext         -mzscheme        +termresponse
+channel         -hangul_input    +netbeans_intg   +textobjects
+cindent         +iconv           +num64           +timers
+clientserver    +insert_expand   +packages        +title
+clipboard       +job             +path_extra      +toolbar
+cmdline_compl   +jumplist        -perl            +user_commands
+cmdline_hist    +keymap          +persistent_undo +vertsplit
+cmdline_info    +lambda          +postscript      +virtualedit
+comments        +langmap         +printer         +visual
+conceal         +libcall         +profile         +visualextra
+cryptv          +linebreak       +python/dyn      +viminfo
+cscope          +lispindent      +python3/dyn     +vreplace
+cursorbind      +listcmds        +quickfix        +wildignore
+cursorshape     +localmap        +reltime         +wildmenu
+dialog_con_gui  +lua             +rightleft       +windows
+diff            +menu            +ruby            +writebackup
+digraphs        +mksession       +scrollbind      +X11
+dnd             +modify_fname    +signs           -xfontset
-ebcdic          +mouse           +smartindent     +xim
+emacs_tags      +mouseshape      +startuptime     -xpm
+eval            +mouse_dec       +statusline      +xsmp_interact
+ex_extra        -mouse_gpm       -sun_workshop    +xterm_clipboard
+extra_search    -mouse_jsbterm   +syntax          -xterm_save
+farsi           +mouse_netterm   +tag_binary      

Pythonパッケージ作りの初歩の初歩

私は、ライトなPythonユーザーなので、pipコマンドでPyPIからパッケージを取ってきてインストールはやるのですが、いまいち、pip/easy_install/distutils/setuptools/setup.pyが一体なんなのか、どう違うのかなど、よくわからないまま、なんとなくpipだけを使ってきていました。

PyPIで何かパッケージを公開することも、特段、他人にパッケージを配布することも、なかったのですが、「パッケージ」について調べたので、ブログにまとめておくことにしました。

と、調べ始めたところ・・・

Python パッケージ管理技術まとめ (pip, setuptools, easy_install, etc)がめちゃくちゃよくまとまってます。
最初これを読んで、情報量が多すぎて圧倒されてしまったのですが、一周回って戻ってきたら、とてもわかりやすくまとまっていて、良いです!!

(自分の記事の存在価値がほぼなくなった・・・)

用語「パッケージ」

最初、私が混乱していた用語が「パッケージ」です。

パッケージ (package) は、Python のモジュール名前空間を “ドット付きモジュール名” を使って構造化する手段です。

https://docs.python.jp/3/tutorial/modules.html#packages

という意味でのパッケージと、もう一つあります。

重要な注意: この文脈で「パッケージ」とは、distribution (つまり、インストールされるひとかたまりのソフトウェア)の同義語であり、Python ソースコード内で import する package (モジュールコンテナ)を指すのではない。Python コミュニティでは、distribution を表すのに「パッケージ」の語を用いるのが普通だ。 “distribution” という用語はしばしば避けられる。というのは、Linux distribution だとか、あるいは Python 自身のような他のより大きなソフトウェアの distribution と混同しやすいからだ。

http://python-packaging-user-guide-ja.readthedocs.io/ja/latest/installing.html

「配布物としてのパッケージの中に、モジュールコンテナとしてのパッケージとその他もろもろ(設定やReadmeやテストなど)を作っておいて、pipでsetuptoolsを利用して、便利にインストールする」という理解でしょうか。

ということで、配布物としてのパッケージ作り方については、
(インターン向けに書いた)Pythonパッケージを作る方法 - Qiita
がとてもわかりやすかったです。

pip

さらに、思い違いをしていたことがありました。それは、pipコマンドでできることです。
PyPIから取ってきてインストールしてくれるのみのコマンドだと思っていました(なんとなくcondaがanaconda cloudからとってきてくれるから、対象サーバーごとのコマンドかと思っていた)。
しかし、そんなことはなくて、ローカルにある自分で作った(配布物としての)パッケージに対しても使えるということです*1

(お前は一体今さら何をいっているんだと怒られそうな予感)

例えば、ローカルにあるパッケージのディレクトリを指定して、

pip install ./mypakage

のようなことをすれば、PyPIに存在していないmypakageをインストールすることができます(./とかをつけて、パスっぽい感じにしてあげるところがポイント)*2

  • -eオプションを使えば、インストールしたふう*3になるそうです(つまり、パッケージをアップグレードしなくても、パッケージのディレクトリの変更が反映されます)
  • ローカルのパッケージだけじゃなくて、gitのリポジトリも指定できるみたいです。
pipと配布物としてのパッケージをつなぐもの

pipはパッケージインストール&管理ツールなのですが、pipがあるおかげで、パッケージの依存関係を解決できて必要なパッケージも一緒にインストールできたり、パッケージのバージョンを指定してインストールできたり、アンインストールできたり*4、アップグレードしたりできるようです。

こういったpipの恩恵に預かるには、ある一定の作法(?)に従って、パッケージに関する情報を記述しておく必要があるようです。

それが、setup.pyというスクリプトであったり、setup.cfg、README.rst、MANIFEST.inといったファイルになるそうです(この辺は、PyPIにパッケージを登録するかしないかで、どのファイルが必要かは変わりそう。)

setup.pyなどに何を記述すべきかというのは、Packaging and Distributing Projects — Python Packaging User Guideが一次情報になるでしょうか。再掲になりますが、(インターン向けに書いた)Pythonパッケージを作る方法 - Qiitaがsetup.pyについて書かれているのがわかりやすかったです。

setup.pyは、現在では、setuptoolsのsetupを呼び出すことをするようです。昔は(?)、ここで使われるツールが、setuptoolsではなくて、distutilsだった模様(今もsetuptoolsの内部的に利用している??)。

その他事項
  • 試しに何かやってみようと思った場合は、venv等で仮想環境作ってから、pip installすることをおすすめします。
  • PyPIは「パイ・ピー・アイ」と読むらしい。PyPyと区別をするためらしい。
  • PyPIに自分のパッケージを登録することもpipのコマンドで行います。(テストPyPIサーバーというものがあって、登録の練習ができるみたいなので、いつかの日のために今度やってみたいですね。)PyPIデビューしたい人の為のPyPI登録の手順 - Qiita
  • 例えばflake8のように、pipで入れると、コマンドになってくれるやつもありますが、setup.pyの中のsetupにentory_pointsを書いて(ちゃんと動くようにやれば)、できるようです。
  • C/C++の拡張もできるみたいです。
  • NumPyは、distutils(Packaging (numpy.distutils) — NumPy v1.14 Manual)があるらしく、Fortran拡張もいける?*5
  • 自前でPyPIっぽいものが欲しい場合は、devpipypiserverといったパッケージがあるらしい。
  • git等の場合は、version等も指定してインストールとかもできる。
(やりたかったこと)

自分で使うようにモジュールコンテナとしてのパッケージを作っていたのですが、あるディレクトリで利用したいときはgit cloneして、また、別のディレクトリで使いたいときは、またgit cloneして・・・と、毎回git cloneするのがめんどくさくて、何かうまい方法がないのかなと思ったのが、今回、パッケージについて調べるきっかけでした。

実態を一つにしておいて、sys.pathに追加するといったことも検討しましたが、これも毎回スクリプトの先頭で追加の部分を書かないといけないのかなーと思っていました。

特に仮想環境等を用意せずにホームディレクトリやどこでもでipythonを起動した時に、import numpyするように、自分のパッケージを利用できたらいいなと思っていたのでした。

その目的を達成する方法としては、自分でsetup.pyまで書いて置いて、そのディレクトリ(かgitリポジトリ)に対して、pip install ./mypackage(-eオプションをつけるかどうかは、やりたいことによると思いますが)でインストールする(できる)というのが、一つの答えなのかなと思いました。

今後の課題
  • setup.pyの書き方をきちんと理解する
    • 依存関係の書き方
    • エントリーポイント
  • PyPIデビュー?


fijixfiji.hatenablog.com

*1:python setup.py installを使ったことがないpip世代

*2:他にもいろいろあるようです。https://packaging.python.org/tutorials/installing-packages/

*3:シンボリックリンク

*4:python setup.py installでインストールできても、python setup.py uninstallはできない。一手間必要。

*5:これはドキュメントのページ発見しただけ

Vimのコマンドまとめを作ってみた

仕事で、一日中使うってわけでもないけれども、Vimをちょいちょい使うようになって、はや一年。
コマンド自体や、やりたいことの名称を知っていればhelpも引けるんだけど、存在を知らないまま、使わずにいる機能ってたくさんあるんだなぁーと、実感することが多いです。

こんな機能あったんだって(自分にとって)発見だったことや、たまにしか使わないから忘れてしまってすぐ毎回ぐぐるコマンドだなーとか、そーゆーものをまとめてみました。

同等機能で、もっと便利な別のプラグインがあるよって場合もあるかとは思いますが、基本的にはデフォルトのvimで使えそうなものに絞りました。

さっそく、vimの起動から!

Vim起動

個人的に、おお!これあったんかい!って感動したヤツは、ssh越しでファイルが編集できる起動方法です(もうひとつは、Exploreでの起動)。

(シェルの)コマンド 意味 補足
$ vim Vimよ、立ち上がれ
$ vim -R file readonlyで起動 消しちゃいけないファイルをうっかり消さないために・・・。
$ vim - 標準出力の結果を取り込んでvimが立ち上がる シェルでなんかのコマンドの出力を受けたりできる
$ vim . Vimでファイルブラウズします。 カレントディレクトリに日付ファイルがだらだら並んでいて、シェルのファイル名補完が微妙に使いにくい場合にかなり重宝する。さらに詳しくは:Explore
$ vim file1 file2 ... 複数のファイルを編集する こうやって起動しても、1つのウィンドウで1つのファイルの編集が始まるだけですが、:argsにファイルのリストがあるよ。
$ vimdiff file1 file2 二つのファイルでdiffをとりつつ起動する :diffsとフォールディングを参照。
$ vim -q fixfile quickfixで開きます この直後は特になにも変化ないけど、:copenでリスト開けます。
$ vim scp://[user@]host/path/filename ssh越しにファイルを編集する userとかhostとかは適宜読み替えください。ちなみに、ルートにアクセスしたければ最後はhost//とスラッシュが2つ。
Vim起動直後のこまったとき編

よくあるのは、文字コードが違って読めないので、別の文字コードで開きなおしたい。ついでに、文字コードutf-8に変換したい。インデントぐちゃぐちゃなので、直したい(保存するかはともかくとして・・・)。の3パターンかなーと思います。

コマンド 意味 捕捉
:e ++enc=utf-8 指定した文字コードで開き直す
:set fileencoding=utf-8 指定した文字コード 文字化けしてない状態で使って、自分はこの文字コードで保存したいんや!というやつ
== インデントなおす gg V G ==みたいな感じで全部選択してやるといい感じになる(ことが多い)。
:Explore

あるファイルを編集しようとして、誤ってディレクトリを指定して起動してしまって、「あああああディレクトリをvimで開いちゃったーとほほ→:q 」と何百回とやったことか・・・。その画面で、カーソルを移動して、ファイル名の上でEnterを押せば、そのファイルが編集できる(個人的にもっと早く気がつきたかった機能No.1)

コマンド 意味 補足
:Explore ファイラーを開きます
:e . 同上 :e fileで編集開始だと知っていれば、Vim起動のvim .の同じ組み合わせ
:Sexplore スプリットなExplore. ウィンドウ操作は、ウィンドウ操作編へどうぞ
:Vexplore :Secploreすると、水平分割ですが、これは垂直に分割されます。 同上

Exploreの画面の操作は、ファイル編集のときと同じように移動(もちろんjk)スクロール・検索ができますし、QuickHelpにも書いてありますが、sを押せば、名前・サイズ・時間で並べ替えできます。詳しくは、ヘルプ読みましょう。*1

追記 ここから
注で「ファイルを誤って開いたあとに、ちゃっと戻る方法ってないんですかね・・・」と書いていたのですが、発見したので、書き残しておきます。

Ctrl-6またはCtrl-^です。

正確には:e #。で、Ctrl-Oとかも検討したのですが。ただし、MacのTerminalだと、Ctrl-6Vimまで届かなくて、何かのショートカットで取られてるみたいです。
ここまで

:args

起動時に渡した引数は、":args"でみることができます。

コマンド 意味 補足
:args 一覧表示だよーん []で囲まれているものが、現在編集中のもの。
:next つぎのファイルに移動するよーん 反対は:previous
:previous 前のファイルに移動するよーん 反対は:next
:first 先頭のファイルに移動するよーん
:last 最後のファイル

あるファイルを編集して、保存せずに移動しようとすると、怒られます。保存して移動は、:wして:nextとしてもよいですが、:wnextみたいなコマンドがあります。破棄して移動は、:next!です。

:diffs[plit]

vimdiff file1 file2で開くこともできますが、画面分割でvimから開くこともできます。

コマンド 意味 補足
:diffs file 水平分割でvimdiffします
:vertical diffs file 垂直分割します

ウィンドウの操作は、「ウィンドウ操作」のところへ。
畳み込みが(たぶん)現れるので、「畳み込み」へ。

畳み込み

僕はほぼ使わないので、現れるのは、vimdiffしたときぐらいで、開けるためのzaと全開のzRしか覚えていない・・・。

ヘルプは、:help fold-commands

アンドゥ/リドゥ
コマンド 意味 捕捉
u アンドゥ
U アンドゥ 一行まとめて
CTRL-R リドゥ
g- 戻る
g+ 進む
:undol[ist] undotreeを表示する 詳しくは、下のサイトを参照。

ファイルごとにundoとかの履歴を残すことができます。
Undoを管理する - Qiita

もう一回やる系(?)
コマンド 意味 捕捉
gv さっきやった選択やり直し 一回囲んでコマンドラインモードを間違えて、全キャンセルしたあととかに、gvしてやり直す。
gi もう一回同じところでインサートモードで入り直す
q: コマンドラインモードの過去の履歴がみれるので :historyでもいいけど、これは表示するだけ。
q/
q?
検索履歴をみる。/と?の違いは、前方/後方検索 http://nanasi.jp/articles/howto/editing/use-command-history.html
:history /で表示するだけ

:historyは、一度ちゃんと把握しておきたい・・・。)
あと、頭にgがつくものは、Vim の g で始まるコマンドというかキーマップの一覧 - Blank Fileにまとめがありました(多謝)。

ウィンドウ操作
コマンド 意味 捕捉
:split 水平分割
:vsplit 垂直分割
CTRL-W CTRL-W ウィンドウ間を移動する これを連打すれば、いつかは望んだウィンドウへ行ける・・・
CTRL-W j 指定した方向のウィンドウへ移動する jklmにかえれば、方向がかわります
CTRL-W CTRL-R 隣接ウィンドウを交換する
CTRL-W J 指定した方向のウィンドウと交換する JKLMにかえれば、方向がかわります
CTRL-W = ウィンドウの幅/高さを等分
CTRL-W + ウィンドウの幅/高さを変える 1回実行ごとの1つずつ(なので、いい感じの回数を頭につける)。+-< >にかえれば、高さ方向だったり幅方向だったり変わる。
CTRL-W _ ウィンドウの幅/高さを最大化 縦ボーに買えたら幅の方向です。
スクロール

ただ単にスクロールするだけなら、画面半分ずつ移動するのがなんとなく好きで、CTRL-UCTRL-Dだけしか使ってないような気がする・・・。yとeがいまいち覚えられない・・・。

スクロールの幅 上へ 下へ
全部 CTRL-B(Backward) CTRL-F(Forward)
半分 CTRL-U(Up) CTRL-D(Down)
1行 CTRL-Y CTRL-E

もうひとつは、見やすい位置にもってくる(つまりカーソルの場所は動かさないで、真ん中にスクロールする)zz。他のコマンドをよく忘れる。これはtopとbottomなので、まだ覚え易いけど・・・。


カーソルの位置を上(Top)ztへ。中央(?)zz、下(Bottom)zbになるようにスクロール。

ジャンプ

人類はもっとvim本来の機能を使うべきだった - うどん よこみち ここがめっちゃ親切にまとめてくれています。

コマンド 意味 捕捉
:ju[mps] jumplistを表示する
CTRL-O きほんのジャンプ 過去にジャンプした場所に戻りたかったら、これを雰囲気で連打
CTRL-I きほんのジャンプ
:tags タグスタック一覧表示 タグジャンプ関連
CTRL-T
:pop
:tag
make/quickfix/vimgrep

qucikfixリストは、makeがあればmakeと実行のところに書いてあるコマンドで作ることができます。
さらに、vimgrepでも作られるようです。vimgrepは、ファイルを横断して、ジャンプする候補を表示してくれるコマンドさんです。

コマンド 意味 捕捉
:make qucikfixリストができます 実行は:make run
:vimgrep // {} リスト生成する //は正規表現の部分。{}は範囲を指定します(*とかやると全部のファイルが対象)
:vimgrepadd // {} 既にあるリストに追加する

quickfixリストの操作方法は、

コマンド 意味 捕捉
:copen 開きます 上でエンター押せば、そこにジャンプする
:cclose 閉じます
:cn[ext] リストの順番で、次の場所にジャンプします
:cp[previous] リストの順番で、前の場所にジャンプします
タグジャンプ

雑な使い方の説明

$ ctags filename  #ファイルを指定した場合
$ ctags -R *      #再帰的にファイルを全部指定した場合

みたいな感じで、tagsのファイルを作っておく。...力つきた(ぱたり

*1:ファイルを誤って開いたあとに、ちゃっと戻る方法ってないんですかね・・・

最近気になってること(2016年12月アップデート版)

自分のアンテナをどっちへむけてはるか確認するという意味で、わりと役にたっている気がするので、定期的に更新しています。

  • インフラ?
    • CentOS 7 (systemctlとかNetworkManagerとか。『CentOS7で作るネットワーク構築ガイド』)
    • サクラのVPS借りたい
    • webサーバ(nginx 『nginx実践入門』)
    • Gunicorn
  • 統計/機械学習
    • PRML
    • Deep Learning / Chiner
    • MCMC / Stan / PyStan
    • Pythonのライブラリ(numpy, scipy, statsmodels, pandas, scikit-learn)
    • matplotlib
    • Jupyter