とある事情で 2014 年末に Python を使って LiveDoor Reader (現 LiveDowango Reader) からインポートできる RSS Reader を作成していたんですが、その時に勉強したまとめを残しておきます。

Python の現在の環境構築から調べてました。なにせ、最後に使ったのは M1 (4、5 年くらい前) の時なので。

開発環境

僕が M1 の時はあまり、外部のライブラリを使ってなかった (そもそも対した事していない) ので殆ど素人の状態から始めました。

その為、一番最初に調べたのは Python のバージョン管理 (実行環境の管理) の方法でした。

pyenv と virtualenv

調べてみると、Python には pyenv と virtualenv という二つのパッケージがある事が分かりました。

下記のサイトを参考にしています。

僕は fish (shell の事) 環境下なので、fish 用のセットアップ方法が必要でした。
同様の環境を使用している方は、pyenv の GitHub に issue がでているので、それを参照して下さい。

pyenv は、Python の実行環境をそれぞれインストールする為のものです。端末内でそれぞれ Sandbox を作成してその中に環境を用意する事も出来ます。ちょっと使ってみた感じでは Ruby の RVM に近いです。

virtualenv はアプリケーション毎にライブラリを管理する事が出来るものです。Ruby では Bundler が同様の立ち位置かと思います。

この二つのアプリケーションが現在の Python の開発環境の主流なのかなという感じです。

ちなみに、Ruby では Gemfile を書いてライブラリのインストールを行なっていましたが、Python では requirements.txt というファイルか、setup.py というファイルによって同様の処理を行なう様です。

調べが足りていないので、現在は

$ pip install hogehoge

でインストールしてから、下記の様に依存関係を吐き出しています。

$ pip freeze -l > requriements.txt

ちなみに、依存関係からインストールを行なう場合は下記のコマンドで出来ます。

$ pip install -r requirements.txt

使用ライブラリ

付随して色々入ってきますが、使用したのはこの辺です。

Flask を選んだのは、Ruby でも Sinatra から入る方が分かり易かったのと、一週間程度の期限で、調べるところからスタートという事を考えてです。

SQLAlchemy は、今後 Python で OR/M を利用する事を考えて、評判の良さそうなものという事で選んでます。
SQLAlchemy Migrate は migrate ツールです。これは SQLAlchemy を使用する事を考えた場合、ワンセットで必要だろうと思い使用しました。

opml は LDR のエクスポートファイルが OPML 形式なので、そのパースを行なってくれるライブラリです。
RssLibraries は RSS の取得、パースを行なうツールです。

作成物

作成物は biwakonbu/pyrss_reader に置いています。

ライブラリの使い方は、ここではしないで、Python そのものの話をまとめておこうと思います。

というのも、言語のお作法で本当に困る事が多いので…
僕は知らなかった init.py、デコレータと、この間研究室の後輩が知らなかった name == “main” の話を書きます。

if name == “main”: について

if __name__ == "main":
  main()

Python でプログラムを書いていると、上記コードは割と見かけるテンプレートだと思うのですが、
この意味を知らない人もいます。

コードの意味のみを見てみると、name という変数の中身に “main” という文字列があるかどうかをチェックしているだけで、
“main” だった場合に main() 関数を実行しています。

そうなると、この name 変数が何か、という事が重要だという事が分かるのですが、いったい何者なんだという話になります。
この問題の name 変数とは、Python によって直接実行されているファイルかどうかを判断する為のものです。

Python では、import を利用してライブラリの読み込みを行うのですが、その際には読み込みを掛けたファイルの中身を実際に実行します。
ただ、その際に全てのコードを実行されるのは具合が悪い時があります。

そういった状況を回避するために導入された変数です。
ですので、直接実行されたプログラム内では、name には “main” という文字列が与えられ、その文字でチェックを掛ける事で
ライブラリとして読み込みを掛けた際には実行しないコードを作成する事が出来ます。

init.py について

僕は最初知らなかったのですが、init.py ファイルは実行されているプログラムより下の階層にあるディレクトリのプログラムを import する際に使用されます。

要するに、Python のライブラリ PATH の解決に利用されているという事です。

勿論、自分で PATH を作成して、import ファイルの PATH を指定する事で読み込む事も出来ますが、
圧倒的に面倒臭いです。

なので、lib/ ディレクトリの様な物を作成する際には、中に空っぽの init.py を作成しておきましょう。
それがあるだけで、そのディレクトリ内のスクリプトは import できるようになります。

デコレータについて

Flask に利用されている機能で、知らなかったので、メモ。
関数を引数として受けとり、関数をデコレーションする機能。

JavaScript で良くある関数オブジェクトを引数として扱うのと同じ話です。Ruby だとイテレータのブロックとかそんな感じ。
コードで言うと下記の様に使います。

def deco(func):
  print "test: " + func()

@deco
def string_deco():
  return "string deco"

@deco
def integer_deco():
  return "integer deco"

実行結果

test: string deco
test: integer deco

Flask ではこんな感じに使ってます。

@app.route('/')
def reader():
  feeds = Feed().query.all()
  entries = {}
  for feed in feeds:
    entries[feed.xmlUrl] = get_links(feed.xmlUrl)
  return render_template('app.html', feeds=feeds, name=FILE, entries=entries)

@app.route の引数によってルーティングと、対応する HTTP メソッドを決める事ができ、
渡す関数の内容によって、その挙動を決定する事が出来るので、非常に分かり易く仕上がっていると思います (僕のコードはさておき)。

これが、デコレータが使われてないと、手続き的に記述するハメになるので、コードを構造化する努力をコーディングする側に押し付ける事になります。

イメージはこんな感じでしょうか。

def reader():
  feeds = Feed().query.all()
  entries = {}
  for feed in feeds:
    entries[feed.xmlUrl] = get_links(feed.xmlUrl)
  return render_template('app.html', feeds=feeds, name=FILE, entries=entries)

app.route('/', reader())

こう見ると、app.route が関数定義から離れた事で、管理対象が二つになったのが一番問題に見えます。
定義の部分と、実行の部分という所ですね。

これがデコレータの機能でまとめられてるのは便利というしか無いです。

まとめ

かなり突貫で物を作る事になり、調べものも多かったですが、非常に有意義ではありました。
Python も久しぶりに触り、前よりも魅力的になった (感じた) 部分や、言語の文化の違いによるコードの書き方など、
思う事も多々ありました。

そして、如何に自分の頭が Ruby 基準になっているのかということも。
これからは Python の記事が多くなっていくとは思いますが、趣味で Ruby は続けます。

二つの言語を横断する事で身に付くプラクティスがきっとあるはずなので。