メモ書き。jedi-vimのjedi部分をRPCで動かすforkを@nakamurayが作ってくれたのでWindowsで動かしてみてた。
https://github.com/nakamuray/jedi-vim/tree/rpc
https://github.com/nakamuray/jedi-vim/tree/rpc2
そのままではWindowsで動かなかったので、手元で少し修正して使った。
virtualenvでも問題なく動作しているのでありがたい。
作業のお供にノンアルコールビール(主にドライゼロ)
この記事はpyspa Advent Calendar 2015の2日目の記事です。
Python温泉は主催者の意向により、酒を飲むのは禁止となってます。
ノンアルコールビールは、酒としてカウントされないのでOKとなっています 。
前回のPython温泉で、「ノンアルコールビールでもドライゼロはうまい」とのタレコミがあり、どれどれと飲んでみたところ、確かにうまい。
参加者たちの間で人気となり、熱海周辺のスーパーマーケットでドライゼロを買い占める集団となってしまいました。
自分も飲んでみて、「これは新しい選択肢だ」と思ったので、この記事で少し紹介したいと思います。
ビールと比べてどうなのか?
ドライゼロの成分表はウェブサイトで確認できます。
アサヒ ドライゼロ | アサヒビール
まず、ドライゼロについては、アルコール分が0.00%でノンアルコールです(0%じゃないノンアルコールもあるので注意しよう)
飲んでも酔いませんし、自動車の運転もできます。
カロリー、糖質も0gとなっています。
後味はすっきりです。ブラックのほうは少し癖がありました。
うまみについては、生ビールと比べると少し物足りなさを感じます。
清涼飲料水やいわゆるノンアルコールの飲み物としてはどうなのか?
では酒ではなく、コーヒーや紅茶、ジュースなどと比べるとどうなのか。
カロリー、糖質が0gとなっている飲み物はノンアルコールビール以外にもありますね。
ノンアルコールビールは、 甘くない(むしろ苦い) カテゴリの飲み物ですね。
コーヒーなどと比べると、 ノンカフェイン の飲み物でもあります。
また、炭酸飲料でもあります。
価格
酒ではないので酒税がかからないため、ビールよりは安いですが、同容量のジュースよりは高めになっているようです。
2015年現在、350ml缶で120円前後で販売されているようです。
飲み物の選択肢として
ノンカロリー、ノンカフェイン、甘くない、炭酸を含む、だとウィルキンソンの炭酸水などが該当しますが、ノンアルコールビールも同様に選択肢としてはありだと思います。
作業のお供に試してみてはいかがでしょうか?
プログラマーは飲み物をつい過剰摂取してしまいがちなデスクワークですし、この機会に飲み物について見なおしてみてはどうでしょうか?
炭酸水のような甘くない炭酸飲料に抵抗がないのであれば、是非ドライゼロを試してみることをおすすめします。
Delphiでインターフェースを使う
久々にDelphiを少し触ってました。かなり忘れてる。
Delphiのインターフェースを使って2つの実装クラスを作り、実行時にどちらのクラスを使うか決定してる。
試したバージョンはDelphi XE4。
Main.dpr
program Main; {$APPTYPE CONSOLE} uses System.Classes, System.SysUtils, System.Generics.Collections; type IStore = interface { データを読み書きするインターフェース } procedure SetValue(Key, Value: String); function GetValue(Key: String): String; end; TStore = class(TInterfacedObject, IStore) { データを読み書きするベースクラス } public procedure SetValue(Key, Value: String); virtual; abstract; function GetValue(Key: String): String; virtual; abstract; end; TMemoryStore = class(TStore) { データをメモリ上にのみ保持するクラス } private StoredData: TDictionary<String, String>; public constructor Create; destructor Destroy; override; procedure SetValue(Key, Value: String); override; function GetValue(Key: String): String; override; end; TFileStore = class(TStore) { データをファイルに保持するクラス } private Loaded: Boolean; FilePath: String; StoredData: TDictionary<String, String>; procedure Load; procedure Save; public constructor Create(FilePath: String); destructor Destroy; override; procedure SetValue(Key, Value: String); override; function GetValue(Key: String): String; override; end; constructor TMemoryStore.Create; begin WriteLn('-- TMemoryStore --'); StoredData := TDictionary<String, String>.Create; end; destructor TMemoryStore.Destroy; begin StoredData.Free; end; procedure TMemoryStore.SetValue(Key, Value: String); begin StoredData.AddOrSetValue(Key, Value); end; function TMemoryStore.GetValue(Key: String): String; begin if StoredData.ContainsKey(Key) then Result := StoredData.Items[Key] else Result := ''; end; constructor TFileStore.Create(FilePath: String); begin WriteLn('-- TFileStore --'); Loaded := False; Self.FilePath := FilePath; StoredData := TDictionary<String, String>.Create; end; destructor TFileStore.Destroy; begin Save; StoredData.Free; end; procedure TFileStore.SetValue(Key, Value: String); begin { データベースの遅延読み込み } if not Loaded then Load; StoredData.AddOrSetValue(Key, Value); end; function TFileStore.GetValue(Key: String): String; begin { データベースの遅延読み込み } if not Loaded then Load; if StoredData.ContainsKey(Key) then Result := StoredData.Items[Key] else Result := ''; end; procedure TFileStore.Load; var Buffer: TStringList; Index: Integer; KeyValuePair: TArray<String>; begin Buffer := TStringList.Create; if FileExists(FilePath) then try WriteLn('Loading database...'); Buffer.LoadFromFile(FilePath); for Index := 0 to Buffer.Count - 1 do begin KeyValuePair := Buffer[Index].Split([','], 2); StoredData.AddOrSetValue(KeyValuePair[0], KeyValuePair[1]); end; finally Buffer.Free; end; Loaded := True; end; procedure TFileStore.Save; var Buffer: TStringList; Key: String; begin Buffer := TStringList.Create; try for Key in StoredData.Keys do begin Buffer.Add(Key + ',' + StoredData.Items[Key]); end; Buffer.SaveToFile(FilePath); finally Buffer.Free; end; end; function StoreFactory(FilePath: String = ''): IStore; begin { FilePathが指定されているならTFileStore、なければTMemoryStoreを使います } if FilePath <> '' then Result := TFileStore.Create(FilePath) else Result := TMemoryStore.Create; end; var Store: IStore; begin { メモリリーク検出 } ReportMemoryLeaksOnShutdown := True; { コマンドライン引数の有無で実装を切り替える } if ParamCount > 0 then Store := StoreFactory(ParamStr(1)) else Store := StoreFactory; { 値の書き込みと取得 } Store.SetValue('MyKey', 'MyValue'); WriteLn(Store.GetValue('MyKey')); end.
実行結果
C:\MyApp>dcc32 Main.dpr Embarcadero Delphi for Win32 compiler version 25.0 Copyright (c) 1983,2013 Embarcadero Technologies, Inc. Main.dpr(169) 170 行, 0.14 秒, コード 919344 バイト, データ 35392 バイト C:\MyApp>Main -- TMemoryStore -- MyValue C:\MyApp>Main database.txt -- TFileStore -- Loading database... MyValue
外部入出力の部分は実装の切り替えができると、自動テストのときに便利です。DIコンテナは大仰だなと思ったら、このぐらいでもいいかもしれませんね。
また、TStoreはTInterfacedObjectを継承しているので、明示的にFreeを呼ばなくても、開放されるようにしています。
通信料金の計算2015年秋
通信料金がいくらぐらいかかっているのか計算などやってたので、メモを残す。
現状の使い方
通信料金
合計: 7095円/月
dulwichを使ってPythonでGitのカスタムコマンドを作る
Gitのコマンドがわかりづらくて好きになれないんですが、気に入らない部分はカスタムコマンドを作ればいいよね。
ということで方法を調べてました。
カスタムコマンドの作り方
Gitのカスタムコマンドは、「git-コマンド名」のような実行可能ファイルを用意して、パスが通ってる場所に置けば有効になるようです。
実行可能であればシェルスクリプトでも問題ないようで、git-flowなどはシェルスクリプトで実装されていますね。
Pythonでdulwichを使ってみる
dulwichはGitリポジトリをPythonで読み書きするためのモジュールです。
Dulwich
Pythonでdulwichを使って実行可能なスクリプトを書くことで、カスタムのGitコマンドをPythonで実装する、というのをやってみます。
試したバージョンは、dulwich 0.11.2, Python 3.4。
dulwichのインストールはpipでvirtualenvにでも入れておけばよいかと。
dulwichの使い方はドキュメントのチュートリアルが参考になります。
Tutorial — dulwich 0.14.0 documentation
以下のようにgit-helloという名前のファイルを作成します。
git-hello:
#!/usr/bin/env python import os import itertools from dulwich.repo import Repo def decode(b): return b.decode('utf8') def main(): print("----- My Git Command! -----") repo = Repo(os.getcwd()) # Walkerを使ってコミットを取得し、id, author, messageを表示する for entry in itertools.islice(repo.get_walker(), 10): print("{}: {}, {}".format( decode(entry.commit.id), decode(entry.commit.author), decode(entry.commit.message).strip())) if __name__ == '__main__': main()
先頭のshebangの部分は、環境に応じて変更すると良いかと思います(virtualenvを使っているなら、virtualenv内のpythonにするとか)
これを適当なディレクトリに置いてパスを通します。今回は $HOME/bin に置きました。
(venv)tokibito@ubuntu:~$ ls -l bin 合計 8 -rwxrwxr-x 1 tokibito tokibito 471 11月 5 23:34 git-hello drwxrwxr-x 5 tokibito tokibito 4096 11月 5 23:07 venv (venv)tokibito@ubuntu:~$ export PATH=$PATH:$HOME/bin
gitリポジトリになっているディレクトリで実行してみると、最近の10件のコミットが表示されました。
試したのは django-ftpserver のローカルリポジトリ。
(venv)tokibito@ubuntu:~/github/django-ftpserver$ git hello ----- My Git Command! ----- a2fa94d4e594d25a9b28203b3a82e5f47b43d67d: Shinya Okano <tokibito@gmail.com>, fixes PEP8, and update version 0.3.2 a8fa3f773714c8b80d8e65cc42c2e5add2b70724: Shinya Okano <tokibito@gmail.com>, Merge pull request #7 from akoumjian/master merged: Custom Authorizer and Handler classes via settings 659e0eb3204a56a56d0946a9ee880a9adb259cc5: Shinya Okano <shinya.okano@beproud.jp>, added: docker settings for test env 9df037ba02770e1bdd0be8e23ed024031a842948: Alec Koumjian <akoumjian@gmail.com>, allow custom authorizers and handlers custom tls add note in docs 8f63fcb3873aa2e9f85870e84a05cf30fc26bb85: Shinya Okano <tokibito@gmail.com>, modify document config 0189b075a633717b27443449558ed6ceda77dbdc: Shinya Okano <tokibito@gmail.com>, update library for documentation 0bc3875f6649db4a0d4234c20a9a14360667e651: Shinya Okano <tokibito@gmail.com>, update version 0.3.1 34d5ef6dc168e43010e4a2e80c346c097671caa7: Shinya Okano <tokibito@gmail.com>, flake8 9c9437f30336abb779871f78ce7d0f39a5e90b17: Shinya Okano <tokibito@gmail.com>, update travis config 664fd42ef583b4f5f2c6ac26827e11ea4f50a4c3: Shinya Okano <tokibito@gmail.com>, modify setup test
こんな感じで、Repoオブジェクトからいろいろ辿れるので、やりたい放題ですね。
A5:SQL Mk-2が便利だった
A5:SQL Mk-2はER図の作成やSQLの実行、結果の表示などができるGUIのツール。Windows用。
ちょっとしたSQLを書くときや、ER図作成のためにWindows用のツールがほしくて、探してたところ見つけた。
しばらく使ってみて、そこそこいい感じだったので紹介する。
A5:SQL Mk-2 - フリーの汎用SQL開発ツール/ER図ツール
MySQLやPostgreSQL、SQLite3、Oracle、SQLServerなど、自分が使うことがありそうなデータベースには一通り対応しているようだ。
PostgreSQLとMySQLとSQLite3で試しているが、DDL生成で一部うまくいかない部分があったけど、データを参照したり追加したりなどの操作では概ね問題ない感じ。
ポータブルで動かす機能や、読み込み専用版が用意されているなど、調査業務でも役に立ちそう。
PyPy3 2.4.0を使ってみた
最近、仕事でPyPy3を試したりしているので、メモを書き残しておく。
PyPy - Welcome to PyPy
インストール
今回はUbuntu 14.04LTSで試した。PyPy3はPPAリポジトリに無いので、Linux向けのコンパイル済みバイナリをダウンロードして使うことにした。
利用するときは、virtualenvでpypy3用の環境を作っている。
$ wget https://bitbucket.org/pypy/pypy/downloads/pypy3-2.4.0-linux64.tar.bz2 $ bzip2 -dc pypy3-2.4.0-linux64.tar.bz2|tar xf - $ sudo mv pypy3-2.4.0-linux64 /opt/ $ sudo ln -s /opt/pypy3-2.4.0-linux64/bin/pypy3 /usr/bin/pypy3
virtualenvで利用する際には --python=pypy3 と指定する。
$ virtualenv --python=pypy3 venv-pypy
互換性について
PyPy3 2.4.0は、CPython 3.2.5互換とのことなので、CPython 3.3以降で導入されたシンタックスが使えないところは気をつけないといけない。
例えば、文字列リテラルに「u」をつけれない点。だたし、これは最初からPython3向けで書いていたコードならそもそも「u」は不要だし、気にしなくてもよさそう。
C言語で書かれたサードパーティ製のモジュールは動かないものが多いので、その場合はPure Pythonのもので代用する必要がある。
今回PyPyを適用したコードは、Python3.4向けに書いていたものであったが、アプリケーションロジックは一行も変更せずに動かすことができた。
互換性は高いと思う。
PyPyを適用するにあたって一点だけハマったところがあった。
「virtualenvでpypy3を動かした際に、出力のリダイレクトを指定するとエンコーディングがasciiになってしまう」というもの。
(venv-pypy)tokibito@ubuntu:~$ python -V Python 3.2.5 (b2091e973da6, Oct 19 2014, 18:29:55) [PyPy 2.4.0 with GCC 4.6.3] (venv-pypy)tokibito@ubuntu:~$ cat test.py import sys sys.stdout.write(sys.stdout.encoding + '\n') sys.stdout.write("日本語\n") (venv-pypy)tokibito@ubuntu:~$ python test.py > hoge Traceback (most recent call last): File "test.py", line 4, in <module> sys.stdout.write("日本語\n") File "/home/tokibito/venv-pypy/lib-python/3/encodings/ascii.py", line 22, in encode return codecs.ascii_encode(input, self.errors)[0] UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) (venv-pypy)tokibito@ubuntu:~$ cat hoge ascii
環境変数のPYTHONIOENCODINGにUTF-8を指定することで回避はできたけど、原因は特定できていない。
virtualenvを使わないでpypy3やpython3.4コマンドで実行すると、特に問題は発生しなかった。
パフォーマンスについて
今回PyPyを適用したコードは、ボトルネックが「2重ループ内での巨大なリストに対する値の参照と比較」となっていたバッチ処理。
データベースの参照やファイル読み込みについては、ループに入る前にすべて読み込んでキャッシュ済みの状態。
データベース接続と問い合わせはDjangoフレームワークのものを使っている。(Django1.8+pymysql)
PyPyを試す前に、cProfileを使って明らかに遅い処理は修正済みの状態。
Python3.4で実行した場合におよそ30分かかっていたもの。
(venv)$ time python manage.py my_script # Python 3.4の場合 real 30m34.483s user 30m34.061s sys 0m0.373s
これをPyPy3で動かした結果、6分程度で終了した。
(venv-pypy)$ time python manage.py my_script # PyPy3 2.4.0の場合 real 6m37.536s user 6m37.238s sys 0m0.289s
この他、同様に600分程度かかっていたバッチ処理が150分程度に短縮されるなど、CPythonの速度がネックになっていた処理はかなり速くなった。