2013/12/29

Python の基本的な高階関数( map() filter() reduce() )

Python の高階関数のうち、組み込みで用意されている基本的なものについてご紹介します。

具体的には
  • map()
  • filter()
  • reduce()
の3つを見ていきます。

個別の説明に入る前に、まずは「高階関数」について少し説明を。

高階関数とは、英語の「 higher-order function 」の訳で、「他の関数を引数として受け取る関数」のことです。たとえば、リストの各要素に共通の処理を加えたリストを作成したい場合なんかに、処理をわかりやすく簡潔に記述することができます。

高階関数の仕組みを用意している言語は他にもたくさんありますが、 Python の場合は「関数はオブジェクトであり、関数に () をつけると初めて関数が呼び出される」決まりとなっています。 () なしで関数の名前だけを指定すればその関数そのものを捉えることができます。

たとえば sin 関数の場合。

print sin(10)  # => sin(10)の計算結果

print sin  # => sin関数を表すオブジェクト

my_sin = sin
print my_sin(10)  # => sin(10)の計算結果

というようなことになります。

では、 map() filter() reduce() の 3 つについて順に見ていきましょう。

map()


map() はリストやタプルの各要素に指定した関数を適用し、各適用結果を順番に返すイテレータを返す関数です。 map(func, iterator) の形で使います。

a = [-1, 3, -5, 7, -9]

print list(map(abs, a))
# => [1, 3, 5, 7, 9]

これは各要素の絶対値を計算する処理をしています。

ここで、 abs() は引数をひとつ取り、その絶対値を返す関数です。 list はイテレータを受け取ってリストとして返す関数(リストのコンストラクタ)です。 list() については、ここでは中身を表示するために使っているだけなので map() の使い方に直接は関係ありません。

map() の戻り値は、リスト a の各要素が abs() に渡された結果の新たなリストとなります( Python3 の場合はイテレータとなります)。

ちなみに、同様の処理をジェネレータ式で書くと次のようになります。

(abs(x) for x in a)  # => map(abs, a) と同じ結果

filter()

つづいて filter() です。 filter() はリストやタプルの要素のうち関数を適用した結果が True となるものだけをイテレータとして返す関数です。
a = [-1, 3, -5, 7, -9]

print list(filter(lambda x: abs(x) > 5, a))
# => [7, -9]
ここでは、無名関数 lambda を使いました。ここで lambda は「絶対値が 5 よりも大きいなら True 」を返す関数です。

filter() の結果として a の要素のうち絶対値が 5 よりも大きいものだけがリストで返ってきています。

ちなみに、こちらもタプル内包表記で書くと次のようになります。
(x for x in a if abs(x) > 5)  # => 上記filterと同じ結果

reduce()

最後に reduce() を見てみます。 reduce() はリストやタプルの要素を足しあわせたりかけあわせたりする関数です。「畳み込み」演算と呼ばれたりします。英語でいうと「 folding 」「 convolution 」でしょうか。

from operator import add
# from functools import reduce  # python 3 では必要

a = [-1, 3, -5, 7, -9]

print reduce(add, a)
# => -5

これはすべての要素を足し合わせるサメーションの計算をしています。

ここで、関数 add は演算子の「 + 」と同じ処理を行う関数です。 Python では演算子である + を reduce に渡すようなことはできないため、 + のかわりに add を使っています。

reduce() の結果として a の要素の総和である -5 が返ってきています。

もちろん、 lambda を使っても同様の処理を行うことが可能です。
print reduce(lambda x, y: x + y, a)

ちなみに、畳み込み演算に対応した内包表記はありません。

追記: Python 3 では reduce() は標準ライブラリ functools に移動されたので、利用するには import してくる必要があります。


おまけ: apply()

Python の 2.3 あたりまでは apply() という関数もあったそうです。しかし、 apply でできる処理は「 * 演算子」(リストなどを展開するスプラット演算子)を使った引数展開によって可能なので(可能となったので?)、推奨されていないようです。

ちなみに、 * 演算子での引数展開は次のように行います。

from operator import add  # addは引数を2つ取る関数

a = [1, 2]

print add(*a)  # => 3
# add は引数を2つ取るインタフェースとなっているため
# リストaを直接受け取ることはできない
# add(*a) とすると a の中身が展開され
# add(1, 2) と同じ動きをする

以上です。


余談ですが、四則演算のための演算子( + - * / )や比較演算子( < <= == >= > )を高階関数に渡したいときは、 operator ライブラリを使うと便利です。演算子と同じ働きをする関数がまとめられています。


参考
高階関数について
高階関数とは - はてなキーワード
高階関数 - Wikipedia
たのしい高階関数

Pythonの高階関数について
2. Built-in Functions — Python公式ドキュメント
Python の map, filter, reduce とリスト内包表記 | すぐに忘れる脳みそのためのメモ
Understanding the Map function. python - Stack Overflow
list - Filters in Python - Stack Overflow

operatorライブラリについて
9.9. operator — Standard operators as functions — Python v2.7.6 documentation

2013/12/23

Python Tips:改行なしで文字列を出力したい

Python の print は、末尾に改行を追加して出力するのがデフォルトの動作となっています。これを改行なしで出力する方法をご紹介します。

方法は2つあります。
  1. print string,
  2. sys.stdout.write(string)

以下、順に見ていきます。


print string,

ひとつめは print string, を使う方法です。
print "hello",
print "hello",
print "hello"
# => hello hello hello

print 文の末尾に「,」をつけると、改行が半角スペースに置き換えられます。これは、いくつもの変数をまとめて表示する際に使える「,」を利用した方法です。
print "hami", "gaki", "ko"
# => hami gaki ko


sys.stdout.write(string)

もうひとつは sys.stdout.write() を使う方法です。
import sys
sys.stdout.write("hello")
sys.stdout.write("hello")
sys.stdout.write("hello")
# => hellohellohello
こちらの方法だと半角スペースが挿入されることもなく、渡した文字列がただそのまま表示される形となります。空白もコントロールしたい場合はこちらを使うのがよろしいかと思います。

ただし、 sys.stdout.write()print 文と異なり、文字列以外を受け取ることができません。文字列になっていないものは str などを使ってフォーマットした上で渡すようにしましょう。

以上です。


上記の方法はあくまでも Python2 でのやり方です。 Python3 の場合は、 print が「 print 文」から「 print 関数」へと変わり、それに合わせて、末尾に追加される文字を end オプションで指定できるようになりました。

Python3 で改行を入れてほしくない場合は次のようにするとよいようです。
# case in Python 3
print("hello", end="")
print("hello", end="")
# => hellohello

ちなみに、 Python2.6 以降であれば、次の一文を宣言すると、 print 文を上書きする形で Python3 の print 関数を使うことができるようになります。
# case in Python 2.6~
from __future__ import print_function
print("hello", end="")
print("hello", end="")
# => hellohello


Python で改行を扱う方法について全般的に知りたい方にはこちらの記事が参考になるかもしれません。

Python Tips: 改行をうまく扱いたい


print に興味のある方はこちらの記事も参考になるかもしれません。

Python 3 の print() 関数の使い方
Python 2 の print 文の使い方


参考
Input and Output - 公式ドキュメント Python Tutorial
print function - Python公式ドキュメント

2013/12/13

ライブラリ:pygooglechart

Pythonの「 pygooglechart 」というライブラリについてご紹介します。

from pygooglechart import *

Gooleが提供しているサービスのひとつに「Google Chart」というものがあります。HTTPリクエストでグラフを生成できるというすてきサービスなのですが、そのGoogle ChartのPython用ラッパーがこの pygooglechart です。

pygooglechart を使えば、ローカル環境にプロット用のツールが入っていなくても、インターネット環境さえあればほんのちょっとのコードでグラフを生成することができます。

以下、使い方をざっと見ていきます。
  • 基本的な使い方
  • 折れ線グラフ
  • 棒グラフ
  • 散布図
  • 円グラフ
  • QRコード
  • 基本的なメソッド

基本的な使い方

まずはもっとも基本的な使い方から。大きな流れは次のとおりとなります。
  • ライブラリの読み込み
  • インスタンスの生成
  • プロットデータの追加
  • 結果の取得

# ライブラリの読み込み
from pygooglechart import Chart
from pygooglechart import SimpleLineChart
from pygooglechart import Axis

# チャートインスタンスの生成
Width = 400
Height = 250
chart = SimpleLineChart(Width, Height)

# プロットデータの追加
chart.add_data([1, 5, 3, 8, 11])
chart.add_data([9, 2, 4, 8, 13])

# 結果の取得
print chart.get_url()  # グラフ画像取得用のURLを表示
chart.download("basic.png")  # 実際に生成されたグラフ画像のダウンロード

上記スクリプトを実行すると、ターミナルにURLが表示され、 basic.png が実行ディレクトリに生成されます。


基本のこの型さえ使えるようになれば、あとは線種やタイトル、凡例などを設定するオプションを都度覚えるだけです。べんり!

以下、さまざまなタイプのグラフを見ていきます。


折れ線グラフ

折れ線グラフの生成には SimpleLineChart というクラスを使用します。

# ライブラリの読み込み
from pygooglechart import Chart
from pygooglechart import SimpleLineChart
from pygooglechart import Axis

# インスタンスの生成
Width = 400
Height = 250
chart = SimpleLineChart(Width, Height)

# プロットデータの追加
chart.add_data([1, 5, 3, 8, 11])
chart.add_data([9, 2, 4, 8, 13])

# 各種オプションの設定
# 折れ線の色の設定
# 16進数表記で与える
chart.set_colours(['333333'])

# 線種を設定
# index は系列の番号 thickness は太さ
chart.set_line_style(index=0, thickness=5)
chart.set_line_style(index=1, thickness=10)

# X軸/Y軸ラベルの追加
# 第1引数に位置を、第2引数にラベルを渡す
# 渡したリストの各要素が自動的に均等配置される
chart.set_axis_labels(Axis.BOTTOM, [0, 1, 2, 3])
chart.set_axis_labels(Axis.LEFT, ["low", "middle", "high"])

# グラフのタイトルの追加
chart.set_title("line chart")

# 結果の取得
chart.download("line.png")



棒グラフ

棒グラフの生成には GroupedVerticalBarChart というクラスを使用します。

# ライブラリの読み込み
from pygooglechart import GroupedVerticalBarChart

# インスタンスの生成
Width = 400
Height = 250
chart = GroupedVerticalBarChart(Width, Height)

# プロットデータの追加
chart.add_data([1, 2, 3, 4, 5, 6])
chart.add_data([1, 25, 9, 16, 36, 4])

# 各種オプションの設定
# 系列ごとの色の設定
chart.set_colours(['333333', 'cc3333'])

# 系列ごとの凡例の追加
chart.set_legend(['x', 'y'])

# 結果の取得
chart.download('bar.png')


ちなみに、折れ線グラフ用のクラスには GroupedVerticalBarChart のほかにも次のようなクラスが用意されています。

  • StackedHorizontalBarChart
  • StackedVerticalBarChart
  • GroupedHorizontalBarChart
  • GroupedVerticalBarChart


棒グラフの伸びる向きや複数の系列をどう表すか、というところがクラスごとに異なる点です。詳細は公式サイトをご覧ください。


散布図

散布図の生成には ScatterChart というクラスを使用します。

# ライブラリの読み込み
from pygooglechart import Chart
from pygooglechart import ScatterChart
from pygooglechart import Axis
import random

# インスタンスの生成
# x_range y_range はX軸/Y軸の範囲を設定するためのオプション
Width = 400
Height = 250
chart = ScatterChart(Width, Height,
                     x_range=(0, 100), y_range=(0, 100))

# プロットデータの追加
# 最初のデータはX軸上の位置 2番目のデータはY軸上の位置 3番目のデータは各点のサイズを表す
NUM_OF_POINTS = 30
chart.add_data([random.randrange(100) for _ in range(NUM_OF_POINTS)])
chart.add_data([random.randrange(100) for _ in range(NUM_OF_POINTS)])
chart.add_data([random.randrange(1, 30) for _ in range(NUM_OF_POINTS)])

# 各種オプションの設定
# ドットの色の設定
chart.set_colours(['333333'])

# X軸/Y軸目盛りの追加
# 第1引数に軸を 第2引数に加減を 第3引数に上限を渡す
# 目盛り幅は自動で与えられる
chart.set_axis_range(Axis.BOTTOM, 0, 100)
chart.set_axis_range(Axis.LEFT, 0, 100)

# 結果の取得
chart.download('scatter.png')



円グラフ

円グラフの生成には、 PieChart2D というクラスを使用します。

# ライブラリの読み込み
from pygooglechart import PieChart2D

# インスタンスの生成
Width = 500
Height = 250
chart = PieChart2D(Width, Height)

# プロットデータの追加
chart.add_data([10, 10, 30, 50])

# オプションの設定
# 各データにラベルを追加
chart.set_pie_labels([
    'ハンバーガー',
    'チーズバーガー',
    'フィレオフィッシュ',
    'ポテト',
    ])

# 結果の取得
chart.download('pie.png')


ちなみに、3Dの円グラフを生成する PieChart3D というクラスも用意されています。


QRコード

QRコードの生成には、 QRChart というクラスを使用します。

# ライブラリの読み込み
from pygooglechart import QRChart

# インスタンスの生成
Width = 250
Height = 250
chart = QRChart(Width, Height)

# QRコードに埋め込むデータの追加
chart.add_data('http://www.google.co.jp')

# 結果の取得
chart.download('qr.png')



この他にもさまざまなグラフが用意されていますが
  • ライブラリを読み込んで
  • ***Chart というクラスのインスタンスを生成して
  • プロットデータを追加して
  • 各種オプションを設定して
  • 結果を取得する
という基本の流れは共通ですので、このあたりをひととおり身につけておけば、ちょっとしたときに使えて便利かと思います。

最後に、ここまでのおさらいも兼ねて使用頻度の高そうなメソッドを見てみます。


基本的なメソッド

add_data(データ系列を表すリスト)
プロットしたいデータを追加するためのメソッドです。データをリスト形式で渡します。

set_colours(16進数表記で色を表す文字列のリスト)
系列の色を設定するためのメソッドです。16進数表記で与えます。複数の系列がある場合は、リストで与えます。

set_title(文字列)
グラフタイトルを追加するためのメソッドです。

set_legend(文字列のリスト)
各系列を説明する凡例を追加するためのメソッドです。

set_axis_labels(Axis.BOTTOMなど, 文字列のリスト)
X軸やY軸にラベルを追加するためのメソッドです。多くの場合は、第1引数に Axis.BOTTOM か Axis.LEFT を、第2引数にラベルのリストを渡します。

set_axis_range(Axis.BOTTOMなど, 下限値, 上限値)
X軸やY軸に目盛りを追加するためのメソッドです。

x_range = (下限値, 上限値)
y_range = (下限値, 上限値)
X軸やY軸の表示範囲を決めるためのメソッドです。デフォルトではすべてのデータが含まれる範囲が自動的に設定されるので、あえてこれを変えたい場合に使います。

get_url()
結果として生成されたグラフ取得用のURLを返すメソッドです。

download(ファイル名)
get_url のURLに実際にアクセスして取得できるグラフ画像を保存するためのメソッドです。ファイル名を渡します。


以上です。


インストール

pip が入っていれば、pip install でのインストールが可能です。
$ pip install pygooglechart


GitHubのリポジトリにはいくつか動くサンプルが入っているので、感触をつかみたい場合には一度そちらで試してみることをおすすめします。


参考
Python Google Chart
gak/pygooglechart - GitHub
Google Charts — Google Developers

のーんびりと Webプログラム: Python Google Chartを使って大量に作成したQRコードをスライドショーで眺めると、QRコードの中に色々な形が見えてきます
Python Google Chart を使って日経225のグラフを描いてみる | 傀儡師の館.Python

2013/12/11

Python Tips:スクリプトとして実行されたときにだけ特定の処理を走らせたい

スクリプトとして実行されたときにのみ走らせたいコードの書き方についてご紹介します。

Pythonのコードを書いていると、そのコードが他からimportされたときには走らせたくないけれど、pythonコマンドで直接実行されたときには走らせたい、という場合があるかと思います。

そのような場合は __name__ 変数を使います。

...

if __name__ == "__main__":
    # その他直接実行されたときにだけ走らせたい処理

__name__ は組み込みの変数で
  • pythonコマンドで直接実行されているとき "__main__"
  • 他のコードからimportされているとき そのファイル名
を文字列として格納しています。

そのため、 if __name__ == "__main__" が True となるのはそのコードが直接実行されたときのみ、となるので、 __name__ によるこのような場合分けが可能となります。


参考
python - What does `if __name__ == "__main__":` do? - Stack Overflow

2013/12/07

Python Tips:Sublime Text 2 のビルドに特定の Python 環境を使いたい

Sublime Text 2 でビルドに使う Python 環境を指定する方法をご紹介します。

Sublime Text 2 では、 Command+BやCtrl+B で編集中の Python ファイルを実行することができます。

その際デフォルトでは環境変数 PATH 上の python コマンドがそのまま使われますが、設定ファイルを編集することによりスクリプト実行に使う Python 環境を指定することができます。

該当する設定ファイルは「 Python.sublime-build 」です。たとえば、この設定ファイルの内容を以下のとおりに変更すると・・・
{
  // "cmd": ["python", "-u", "$file"],
  "shell": true,
  "cmd": ["source ~/.bashrc && workon name_of_virtualenv && python -u \"$file\""],
  "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
  "selector": "source.python"
}

name_of_virtualenv には使いたい virtualenv 環境名を記入してください。

これで、 virtualenvwrapper で作成した特定の Python 環境が使われる形となります。

ただし、以下の 2 点が前提条件となります。

  1. virtualenvwrapper がインストールされている
  2. virtualenvwrapper 有効化スクリプトが .bashrc に書き込まれている


以上です。

ここでご紹介したのは virtualenvwrapper を使う場合ですが、 virtualenvwrapper を使わずに直接変更する場合は

  • 環境変数 PATH の先頭に使いたい Python 環境へのパスを追加
  • python -u のところの python を使いたい Python 環境の python に変更

するとよいでしょう。

ちなみに、 Sublime Text の設定ファイルを触ったことがあまりない場合は、念のためにバックアップを取ってからの編集がおすすめです。

Build Systems — Sublime Text Unofficial Documentation


追記 2017/11:

Sublime Text の定番・おすすめパッケージのリストを作りました。 Sublime Text をお使いの方はよろしければご参考にどうぞ。

おすすめ Sublime Text パッケージ | gotohayato

2013/12/04

Python Tips:csvファイルを扱いたい

Pythonでcsvファイルを扱う方法をご紹介します。

csvを扱うには、名前もそのままの csv ライブラリが便利です。

csvを使うおおまかな流れは次のような形となります。
  1. ファイルオブジェクトを開く
  2. ファイルオブジェクトをcsv.reader()かcsv.writer()に渡す
  3. 生成されたcsvオブジェクトのメソッドを使う
  4. ファイルオブジェクトを閉じる

いちばんシンプルなcsvの読み込みは次のような感じになります。
import csv
with open(FILENAME, 'r') as f:
    c = csv.reader(f)
    for row in c:
        print row
この場合は各rowが配列として帰ってきます。デフォルトでは各要素は文字列なので、数値として扱いたいときには
    for row in c:
        num_row = map(float, row)  # 各要素をfloatに変換
        print num_row
などとするとよいかと思います。

先頭行がデータではなくカラム名になっているかどうかを調べたいときは、csv.Snifferクラスのhas_header()メソッドにファイルの中身を渡すこととある程度自動判定してくれます。
    hasHeader = csv.Sniffer().has_header(f.read(100))
    if hasHeader:  # header行があるかどうか True/False
        print "%s has a header" % FILE
        f.seek(0)  # 先頭に戻る

書き込みの方法や区切り文字の指定方法等々は csvライブラリ のところにも書いたので、よろしければそちらもご覧ください。

csvライブラリ

2013/11/30

Python Tips:リストから重複した要素を削除したい

Pythonで、リストから重複した要素を取り除き、ユニークな要素だけを持つリストを得る方法をご紹介します。

いちばんカンタンでPythonらしい書き方は set を使うパターンでしょうか。
li = [3, 4, 3, 2, 5, 4]
li_uniq = list(set(li))  # [2, 3, 4, 5]
いったんsetにすることで重複要素が自動的に削除されます。

ただしこの方法だと要素の順番が変わることもあるようです。要素の順番を保ちたい場合には、普通にforループを回す形になります。
li = [3, 4, 3, 2, 5, 4]
li_uniq = []
for x in li:
    if x not in li_uniq:
        li_uniq.append(x)
li  # => [3, 4, 2, 5]

StackOverflowでは、リスト内包表記を使う方法や高速化する方法が議論されています。

たとえば、内包表記を使ってかつ高速化する方法として次のようなやり方が紹介されています。
def f7(seq):
    seen = set()
    seen_add = seen.add
    return [ x for x in seq if x not in seen and not seen_add(x)]

seen_add = seen.add あたりはオブジェクトのアトリビュート参照の時間も削減しよう、という試みでしょうか。


参考
Get unique values from a list in python - StackOverflow
In Python, what is the fastest algorithm for removing duplicates from a list so that all elements are unique *while preserving order*? - StackOverflow
How do you remove duplicates from a list in Python whilst preserving order? - StackOverflow

2013/11/26

Python Tips:Sublime Text 2でvirturalenv環境のPythonを使いたい

Sublime Text 2でPythonのコードを書いていると、ショートカット(Ctrl+b や Command+b)で走るPythonを指定したいことがあります。

今回はその例として、virtualenv環境のPythonを使う方法をご紹介します。

1 Python.sublime-build の設定
{
  // "cmd": ["python", "-u", "$file"],
  "shell": true,
  "cmd": ["path/to/virtualenv/bin/activate && python -u \"$file\""],
  "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
  "selector": "source.python"
}
デフォルトの設定は、コメントアウトしてある最初の「cmd」の行です。それをコメントアウトし、新たに「shell」というプロパティを追加、「cmd」プロパティを再設定します。

「&& python」の前の「path/to/virtualenv/bin/activate」の部分にvirtualenv環境を読み込むコマンドを記述します。ちなみに、私の環境ではbashシェルを使っていて、.bashrcの中でvirtualenv環境を有効にしているので、この部分には単純に「source ~/.bashrc」を入れています。

ポイントは、デフォルトではcmdの値は複数の要素を持つ配列になっているのですが、変更後はひとつの文字列だけを持つ配列に収める、というところです。他のシェルは試していませんが、bashの場合は複数の要素を持つ配列にするとうまく動いてくれません。


参考
Build Systems - Sublime Text Help
Build Systems - Sublime Text Unofficial Documentation

2013/11/19

Python Tips:ターミナルのコマンドを利用したい

Python上でターミナル(コマンドライン)のコマンドを利用できる機能についてご紹介します。

import subprocess 

subprocess.call(cmd)
subprocess.check_call(cmd)
subprocess.check_output(cmd)

コマンド関連の機能はsubprocessの中にまとめられています。代表的なものはcall、check_call、check_outputの3つでしょうか。

subprocess.call('ls')
# ただ実行するだけ 
# 結果ステータスを返す
# 0なら成功
subprocess.check_call('ls')
# call とほとんど同じだが
# エラーなら CalledProcessError 例外をあげてくれる
subprocess.check_output('ls')
# check_call とほとんど同じだが
# コマンドの標準出力を返す

callがいちばんシンプルで、check_call、check_outputになると機能が豊富になっていきます。callは実行してステータスを返すだけ、check_outputは出力を文字列で取得できエラーの例外処理もPython上で行うことができます。

例外処理や出力の再利用のことなんかを考えると、通常はcheck_outputを使うのが良さそうです。

コマンド関連の機能がsubprocessモジュールにまとめられる以前は、osモジュール内のos.systemやcommands内のgetstatusoutputなどがありましたが、現在では推奨されていないようです。

import os
os.system('ls')
# ステータスを返す
# subprocess.call('ls') に近いもの
import commands
commands.getstatusoutput('ls')
# ステータスと出力をリストにして返す
# subprocess.check_output('ls') に近いもの

その他、サブプロセスをもっと細かく扱いたい場合には、Python 3の場合はsubprocess.Popenクラス、Python 2の場合はpopen2モジュールを使うのがよいようです。


参考
subprocess - Python公式ドキュメント
os - Python公式ドキュメント
commands - Python公式ドキュメント
Python pythonからシェルコマンドを叩く - かぴぶろぐ

2013/10/07

ライブラリ:sqlite3

Pythonの「sqlite3」というライブラリについてご紹介します。

import sqlite3

「sqlite3」はその名前のとおり、Pythonで「sqlite」を使うためのライブラリです。Pythonとsqlite3コマンドが入っていれば、特別な準備なしで使いはじめることができます。

以下、基本的な使い方を見ていきます。
  • データベースへの接続
  • テーブルの作成
  • レコードの挿入
  • レコードの参照
  • レコードの更新/削除

データベースへの接続

import sqlite3

print u'データベースへの接続'
con = sqlite3.connect("test_data.db")
SQLiteのデータベースに接続するには、connect()という関数を使います。

connect()を実行すると、ファイルが存在する場合にはそこに接続し、存在しない場合には新規に作成してくれます。

con.close()
処理が終わって接続を閉じるときにはclose()を使います。ファイル操作と同じように、一連の処理が終われば必ず最後に閉じる処理を行います。

テーブルの作成

データベースに接続したあとの処理は、原則的に関数execute()を通して行います。

テーブルの作成の場合も例外ではなく、execute()にSQL文を書いて渡します。
print u'テーブルの作成'
sql = u"""
create table dogs (
    id integer primary key autoincrement,
    name varchar(20),
    age integer
);
"""
con.execute(sql)
ここではSQLiteの文法についての詳細は割愛しますが、ここでは「dogs」というテーブルを作って、その中に「id」「name」「age」という3つのカラムを作成しました。

ちなみに、テーブルの削除もそのままSQL文を投げる形で行います。
print u'テーブルの削除'
sql = u"""
drop table dogs;
"""
con.execute(sql)

レコードの挿入

レコードの挿入は頻繁に行う処理なので、いくつかのやり方が用意されています。

print u'レコードの追加01'
sql = u"insert into dogs values (null, 'taro', 23)"
con.execute(sql)
con.commit()
使い切りのフォーマットでレコードをひとつだけ挿入する場合は、上記のとおりに行うとよいかと思います。

print u'レコードの追加02'
sql = u"insert into dogs values (null, ?, ?)"
con.execute(sql, (u"jiro", 10))
con.execute(sql, (u"hanako", 22))
con.commit()
統一されたフォーマットで複数の異なるレコードを挿入したい場合は、フォーマットと実データとを分けて渡すこともできます。SQL文の「?」の部分に、タプルの中身が順番に挿入されます。

この他にも「executemany()」という関数があり、これを使うともっとたくさんのレコードをまとめて挿入することができます。詳しくは公式ドキュメントの該当箇所をご覧ください。

レコードの参照

レコードを参照するときも、execute()にSQL文を渡せばOKです。

import pprint 

print u'レコードの参照01'
c = con.execute(u"select * from dogs")
for row in c:
    pprint.pprint(row)
# 次のとおり表示
# (1, u'taro', 23)
# (2, u'jiro', 10)
# (3, u'hanako', 22)
戻り値から要素をひとつずつ取得すると、各レコードがタプルとして返ってきます。

print u'レコードの参照02'
c = con.execute(u"select * from dogs where age > 15")
for row in c:
    pprint.pprint(row)
# 次のとおり表示
# (1, u'taro', 23)
# (3, u'hanako', 22)
where句なども問題なく使うことができます。

print u'レコードの参照03'
c = con.execute(u"select * from dogs")
row = c.fetchone()
print row  # (1, u'taro', 23)
fetchone()を使えば、引っかかったものの中からひとつだけを取得することなんかもできます。

レコードの更新/削除

挿入と同じく、更新や削除もそれぞれupdate、deleteを使うことによって行うことができます。
print u'データの更新'
con.execute(
    u"update dogs set age=13 where name='google'")
con.commit()

また、データベースといえば、コミット、ロールバックですが、commit()の代わりにrollback()という関数を使うとロールバック処理も行うことができます。

以上です。


このsqlite3は非常にカンタン・便利なライブラリですが、SQLiteについてよく知らない状態で使い始めるとちょっと大変かもしれません。本格的に使うのであれば、まずSQLiteについて正しく学んでから使うのがよろしいかと思います。
SQLite
SQLite入門 - ドットインストール
SQLite入門(アプリケーション編) - slideshare


インストール
Python 2.5以上であればデフォルトでインストールされるので、別途インストールは不要です。


参考
sqlite3 - Python公式ドキュメント
A Simple Step-by-Step SQLite Tutorial - Mouse vs. Python
SQLite3を使用する - Python Tips

2013/10/02

ライブラリ:chardet

Pythonの「chardet」というライブラリについてご紹介します。

import chardet

「chardet」は、ファイルやページの文字コードを判定するためのライブラリです。「CHARacter DETection」の略ですね。

「コマンドラインで使う使い方」と「コードの中で使う使い方」の2通りがあります。まずはコマンドラインで使うやり方から見ていきます。

コマンドラインで使う

chardetect.py sample.txt
chardetをインストールしたら、コマンドラインでchardetect.pyが使えるようになっているかと思います。

それにファイル名を渡せば、文字コード判定結果を返してくれます。

判定結果は
「ファイル名: 文字コード with confidence 数値」
という形で返ってきます。文字コードの部分が判定した文字コード、数値の部分が信頼度で、0以上1以下の数値となっています。

chardetect.py sample1.txt sample2.txt sample3.txt
複数のファイルを渡せば、文字コードをまとめて判定することも可能です。前から順番に、各ファイルの判定結果が返されます。

コードの中で使う

import urllib
import chardet

rawdata = urllib.urlopen('http://www.1101.com/').read()
print chardet.detect(rawdata)
{'confidence': 0.98999999999999999, 'encoding': 'SHIFT_JIS'}
コードの中で使うには、chardet.detect()を使います。ファイルやインターネットから取り込んだデータを渡すと、結果を辞書にして返してくれます。


以上です。


インストール
pipが入っていれば、
pip install chardet
でインストールすることができます。


参考
chardet - PyPI
chardet - Github
文字コードを推定する - 逆引きPythonメモ

2013/09/26

ライブラリ:see

Pythonの「see」というライブラリについてご紹介します。

from see import see

「see」は、標準の関数「dir」の改良版「see」関数を提供するライブラリです。

「dir」は手軽に使えてよいのですが、出力結果が見やすくないところがたまにきずです。。そんなdirの見栄え部分を改善したのがこの「see」です。

以下、使い方を見ていきます。使い方はとてもシンプルです。

from see import see

a = list()

print 'dir():'
print dir(a)
# dir():
# ['__add__', '__class__', '__contains__', '__delattr__', 
# (一部のみ)

print 'see():'
print see(a)
# see():
#     []           in           +
#     <            <=           ==
#     hash()       help()       iter()
# (一部のみ)
dirを使うと「'__add__'」といったデフォルトのメソッド名がそのまま表示されますが、seeではそれが「+」といった人が見てわかりやすい表記に変換されて出力されます。さらにseeだと結果がきれいに整形されて出てきます。
print 'see(var, ".re*"):'
print see(a, '.re*')
# see(var, ".re*"):
#     .remove()     .reverse()
seeの第2引数にワイルドカードを含む文字列を渡すと、マッチした名前だけがずらずらっと表示されます。上記の場合ですと、「re」で始まる名前のもののみが表示されています。

以上です。


インストール
pipが入っていれば
pip install see
でインストール出来ます。


参考
see()

2013/09/25

ライブラリ:PIL

Pythonの「PIL」というライブラリについてご紹介します。

from PIL import Image

「PIL」は画像データを扱うため機能をひとまとめにしたライブラリです。名前の「PIL」は「Python Imaging Library」の省略形です。

bmp、tiff、gif、jpg、pngといったメジャーなフォーマットでの読み書きにはひととおり対応しており、機能が豊富なので、「Pythonで画像処理といえばPIL」といった位置づけになっているようです。

以下、基本的な使い方をざっくりと見ていきます。

画像の読み込み

from PIL import Image

image = Image.open('lenna.png')
print image.__class__
# PIL.PngImagePlugin.PngImageFileと表示
Image.open()で画像データを読み込むことができます。PngImageFileクラスなどのインスタンスが生成されて返されるので、その後はそのインスタンスに対して処理を施していきます。

画像の表示

image.show()
show()メソッドで画像を表示することができます。OSでその画像フォーマットに関連づけられているソフトが起動します。

画像の保存

image.save('lenna_changed.png')
save()メソッドにファイル名を与えれば、画像を保存することができます。

画像のメタ情報へのアクセス

print image.filename  # lenna.pngなどと表示
print image.format, image.size, image.mode
# PNG (220, 220) RGBAなどと表示
ファイル名(ある場合のみ)や画像フォーマット、サイズやカラーモードなどのメタ情報は、各種アトリビュートの中に入っています。image.modeは「L」「RGB」「CMYK」などの値を取り、Lならグレースケール、RGBならRGB、CMYKならCMYKなどのカラーモードを意味します。

for k, v in image.info.items():
    print k, v
# たとえば以下のとおり表示
# aspect (72, 72)
# gamma 0.45455
画素のアスペクト比、ガンマ値などの情報はinfoの中に入っています。

画素データへのアクセス

画素データにアクセスするには、大きく2通りの方法があります。ひとつはgetdata()、もうひとつはgetpixel()です。

px = image.getdata()
print px[3]  # (227, 138, 125, 255)などと表示
getdata()を使うと、すべての画素データを1列にまとめて取得することができます。getdata()とは逆にデータを書き込む方はputdata()メソッドです。

image.getpixel((x, y))
getpixel()だと、1画素単位で情報を取得することができます。取得とは逆にセットする方はputpixel()で行えます。

画像の新規作成

image = Image.new("RGB", (100, 100))
image.show()  # まっさらの画像が表示される
new()メソッドにカラーモードとサイズを渡せば、画像を新規作成することができます。

画像の統計値へのアクセス

from PIL import ImageStat

stat = ImageStat.Stat(image)
print 'pixel num:', stat.count
print 'pixel sum:', stat.sum
print 'pixel mean:', stat.mean
print 'pixel variance:', stat.var
print 'pixel stddev:', stat.stddev
# それぞれRGBAの統計値がタプルに収められて返される
ImageStat.Stat()という関数を使うと、画素の統計情報をまとめて取得することができます。countは画素の総数、sumは合計、meanは平均、varやstddevは分散や標準偏差をそれぞれ格納しています。

以上です。

この他にも、回転、拡大縮小、切り取り、明るさ・コントラストの調整といったことができます。文字や図形の書き込み、ふたつの画像の重ね合わせといった少し凝った処理なんかもメソッドひとつでできたりするので、基本的な使い方をひととおり覚えておくと便利です。


インストール
pipが入っていれば
pip install PIL
でインストールできます。


参考
PIL
Python Imaging Library Handbook
Python Imaging Library (PIL) 利用ノート - プレハブ小屋
画像処理でのPythonの利用 - slideshare

2013/09/12

ライブラリ:Requests

Python の「 Requests 」というライブラリについてご紹介します。

Python Requests

import requests

Requests は「 HTTP for Humans 」のキャッチコピーのとおり、 HTTP リクエストを人間が直感的に行えるように作られたライブラリです。インタフェースが洗練されており、かんたん・シンプルに使えるのが特徴です。

GitHub では 5,000 以上もの Star がつけられており、 Python 用のライブラリとしては Django や Flask に並ぶ最も人気の高いもののひとつかと思います。「 Python の好きなライブラリは?」という質問に対してこの Requests をあげる人も多いようです。

Python の HTTP リクエスト用のライブラリとしては、 Requests が作られる前から urllibhttplib などが存在したのですが、使い方がいまいちわかりづらい、とのことからこの Requests ライブラリが生み出されたようです。

以下、 Requests の基本的な使い方を見ていきます。

インストール


pip が入っていれば pip コマンドでそのままインストールが可能です。

pip install requests


GETリクエスト


import requests

r = requests.get('http://docs.python-requests.org/en/latest/')
print r.status_code  # 200
print r.headers  # ヘッダ情報を辞書型として格納
print r.encoding  # ISO-8859-1
GET リクエストは requests.get() という関数で行えます。 HTTP レスポンスの情報を格納した独自の Response オブジェクトが返ってくるので、その変数のアトリビュートやメソッドにアクセスする形で結果を利用することができます。

Response オブジェクトのアトリビュートのうち、 status_code はステータスコードを、 headers はヘッダ情報を、 encoding は文字コードを格納しています。

レスポンスボディの取得


r = requests.get('http://docs.python-requests.org/en/latest/')
print r.text
print type(r.text).__name__  # unicode

Response オブジェクトの text にはレスポンスのボディ部分が格納されています。ボディは自動的に unicode 化されているので、上述の encoding というのは unicode 化前の原文の文字コードを表します。

bytes データとしてのボディの取得


r = requests.get('http://docs.python-requests.org/en/latest/')
print r.content
print type(r.content).__name  # str

Response オブジェクトの content アトリビュートには、レスポンスボディの bytes 形式でのデータが格納されています。

JSON 形式でのボディの取得


r = requests.get('http://www.lifewithpython.com/feeds/posts/default?alt=json')
print r.json()
print type(r.json()).__name__  # listもしくはdict

JSON を返す URL にアクセスしたときの Response オブジェクトで json() メソッドを呼び出すと、 JSON データを parse
したものを返してくれます。データ型は通常の list 型あるいは dict 型となります。

POST/PUT/DELETE リクエスト


r = requests.post(URL_TO_POST)
r = requests.put(URL_TO_PUT)
r = requests.delete(URL_TO_DELETE)
r = requests.head(URL_TO_HEAD)
r = requests.options(URL_TO_CHECK_REQUEST_OPTIONS)

GET 以外の POST/PUT/DELETE/HEAD などのリクエストは、それぞれその名前の関数で行うことができます。直感的!

GETリクエストクエリの設定


payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print r.url  # u'http://httpbin.org/get?key2=value2&key1=value1'

GET リクエストのクエリを指定したい場合は get() 関数の呼び出し時に「 params 」引数に dict を渡します。最終的にどのような
URL が生成されているかは url アトリビュートで確認することができます。

POST リクエストデータの設定


payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post("http://httpbin.org/post", data=payload)

POST リクエストの際の送信データの指定には post() 関数の引数「 data 」を使用します。こちらも GET クエリの場合と同じく dict を渡します。

以上です。




ここでご紹介したもの以外にもさまざまな機能が用意されていて、高機能でかつわかりやすい、とても pythonic なライブラリとなっています。より詳しく知りたい方は公式のドキュメントをご覧になってみてください。

Requests に興味のある方には次のページも参考になるかもしれません。

Python Tips:Requests ライブラリのレスポンスボディの文字化けを解消したい


参考
Requests: HTTP for Humans
Requests - github

2013/09/07

ライブラリ:PyQuery

Pythonの「PyQuery」というライブラリについてご紹介します。

from pyquery import PyQuery

「PyQuery」はその名前のとおり、「Python + jQuery」なライブラリ。jQueryのような機能をPython上で提供してくれます。

「$('.myclass')」といったあのシンプルでわかりやすいAPIをPython上でも同じように使うことができます。

以下、基本的な使い方を見ていきます。まずはインスタンスの生成から。

01 PyQueryインスタンスの生成

from lxml import etree
from pyquery import PyQuery as pq

d1 = pq("<div>")
print d1  # <div/>
print type(d1)  # <class 'pyquery.pyquery.PyQuery'>
PyQueryの利用は、PyQueryクラスのインスタンス生成から始まります。「$(タグ名)」でタグ名によって生成することができます。

e = etree.Element("body")
d2 = pq(e)
print d2  # <body/>
lxml.etreeのElementインスタンスから生成することもできます。

d3 = pq(url='http://google.co.jp/')
print d3  # 指定したページのソースが表示される
URLをもとに生成することなんかもできます。

さらに、「filename」キーワードを使えば、ローカルのHTMLファイルから生成することもできるようです。このあたりの詳しいところは、ソースの該当部分をごらんいただくのがよいかと思います。

02 オブジェクトの操作: 子要素の追加

d2.append(d1)
print d2  # d2の子としてd1が追加される
append()やprepend()を使うと、PyQueryインスタンスに子要素を追加することができます。

d2.prepend(pq('<header/&;gt'))    # d2の子の先頭にheaderが追加される
d2.append(pq('<div>'))  # d2の子の末尾にdivが追加される
d2.append(pq('<footer/&gt'))  d2のこの末尾にfooterが追加される
print d2
# 以下のとおり表示
# <body><header/><div/><div/><footer/></body>

02 オブジェクトの操作: 子要素の取得

for ele in d2.children():
    print ele.tag
# 以下のとおり表示
# header
# div
# div
# footer
要素の子要素はchildren()メソッドで取得することができます。

02 オブジェクトの操作: 子孫要素へのアクセス/内容の編集

d2('div').addClass('article')
d2('.article').text('--- in div ---')
jQueryの「$( )」での要素検索と同じことが、PyQuery上でもできます。$('abc')は要素abcを、%('.abc')はクラスabcを探してきます。

d2('header').addClass('headerA')
d2('.headerA').html('archive')
addClass()、text()、html()といった、jQueryでお馴染みの便利なメソッド群も使うことができます。

02 オブジェクトの操作: CSS属性の編集

d2.attr('color', '#222')
print d2
# 以下のとおり表示
# <body color="#222"><header class="headerA">archive</header>
タグ属性の変更もjQueryと同じ形でできます。

以上です。

厳密にjQueryと同じインタフェースが実現されているわけではありませんが、大方似たような感覚で使えます。jQueryをすでによく知って使っている方にとっては、とっつきやすいライブラリのひとつではないかと思います。


インストール
pipがある場合はpipを使うのがよいかと思います。
pip install pyquery

PyQueryの利用には「lxml」というライブラリも必要となりますので、それが入っていなければ事前にインストールしておきましょう。ちなみにlxmlのインストールにはCコンパイラなどが必要とのことで、Windows環境の場合なんかにはpipよりも実行形式のインストーラを使うのがおすすめです。


参考
PyQuery
PyQuery - PyPI

2013/09/03

ライブラリ:lxml.etree

Pythonの「lxml.etree」というライブラリについてご紹介します。

import lxml.etree

「lxml.etree」は、XML形式のデータをPythonで手軽に扱えるようにするためのライブラリです。XML形式のデータがカンタンに扱えるさまざまな機能を備えています。

私は、jQueryと同等の機能を提供する「PyQuery」というライブラリを使うのに必要だったので入れました。

以下、etreeの基礎的な使い方を見ていきます。

01 インスタンスの作成

etreeの基本となるのは「Element」と呼ばれるクラスです。
from lxml import etree

root = etree.Element("root")
print type(root).__name__  # _Elementと表示
print root.tag
Element()に文字列を渡せば、その名前のElementインスタンスを作ることができます。

その要素のタグには、「tag」というアトリビュートでアクセスできます。

02 子要素の追加

child1 = etree.SubElement(root, "child1")
root.append(etree.Element("child2"))
root.insert(0, etree.Element("child3"))
print etree.tostring(root, pretty_print=True)
# 次のとおり表示
# <root>
#   <child3/>
#   <child1/>
#   <child2/>
# </root>
子要素を追加するには、SubElement()、append()、insert()といったメソッドを使います。SubElementはインスタンス生成時に親を特定して作るもので、append()とinsert()は、親要素のメソッドとして呼び出し、子要素を引数に受け取るカタチで使います。

append()とinsert()は、list型のメソッドと同じ使い方で使うことができます。

特定の要素を子要素も含めて整形して表示するには、etree.tostring()を使います。

03 テキストとコメント要素

child4 = etree.SubElement(root, "child4")
child4.text = "this is text"
root.append(etree.Comment("comment part"))
print etree.tostring(root, pretty_print=True)
# 次のとおり表示
# <root>
#   <child3/>
#   <child1/>
#   <child2/>
#   <child4>this is text</child4>
#   <!--comment part-->
# </root>
要素内のテキストには、textアトリビュートを使ってアクセスすることができます。また、コメント要素を表すクラスとしてCommentというものがあります。こちらもElementと同じようにほかの要素の子要素とすることができます。

04 子要素へのアクセス

print root[0].tag  # 
print len(root)  # 5
print root.index(root[2])  # 2
特定の要素の子要素には、インデックスを使ってアクセスすることができます。

children = list(root)
for c in children:
    print c.tag
# 次のとおり表示
# child3
# child1
# child2
# child
また、Elementを関数list()に渡すとその子要素のリストを作ることができます。

05 属性値へのアクセス

root.set("hello", "world")
root.set("dog", "taro")
a = root.attrib
print a  # {'hello': 'world', 'dog': 'taro'}
print a.get("dog")  # taro
属性値には、set()、get()などを使ってアクセスすることができます。また、属性値のセットを辞書として取得するにはattribアトリビュートを使います。

06 要素間の移動

print root[1].getnext().tag  # child2
print root[1].getprevious().tag  # child3
print root == root[1].getparent()  # True
要素間の移動をするためのメソッドとしては、getnext()、getprevious()、getparent()などが用意されています。


以上です。


インストール
ソースからインストールする場合は、pipやGithubでインストールするようです。

私は主にWindowsで使っているのですが、Windowsの場合はコンパイラの設定などがややこしいので、有志で作られているインストーラを使いました。Windowsはこちらが手早いかと思います。
lxml 2.3 - PyPI
lxml - Unofficial Windows Binaries for Python Extension Packages


etreeのほかにも、lxmlにはさまざまな便利なサブモジュールがあるようですので、詳しくは公式ドキュメントをごらんください。


参考
lxml - XML and HTML with Python
lxml - PyPI
lxml 2.3 - PyPI
lxml - Unofficial Windows Binaries for Python Extension Packages

2013/08/26

ライブラリ:loremipsum

Pythonの「loremipsum」というライブラリについてご紹介します。

import loremipsum

loremipsumは、サンプル文字列を生成するためのライブラリです。名前から想像がつく方もあるかと思いますが、そのまま、「lorem ipsum...」的なランダムな文章を生成してくれます。

使う機会はあまり多くないかと思いますが、ランダムな文章をあてでどこかに入れたいときなんかに便利です。

以下、主な使い方を見ていきます。

サンプル文の生成

s1 = loremipsum.get_sentences(4)
for row in s1:
    print row
# たとえば次のとおり表示
# Risus fames risus lorem risus nibh nunc.
# Donec dolor diam.
# Felis porta vitae.
# Ipsum velit quisque libero fusce et.
get_sentence()関数は、引数に渡された整数値の数のサンプル文をリストにして返してくれます。

サンプルパラグラフの生成

p1 = loremipsum.get_paragraphs(3)
pprint.pprint(p1)
get_sentence()が「.」(ピリオド)までの文を一単位として返すのに対し、get_paragraphs()は、複数の文がまとまった「段落」ひとつの単位として、渡された整数値の分だけ段落を返してくれます。こちらも返ってくる形式はリストです。

もっと深く使う

from loremipsum import Generator
g = Generator()
sample = g.generate_paragraph()
print sample
単語辞書を与えたりなどして、より柔軟に使えるサンプル文章機能を提供するGeneratorクラスも存在します。generate_paragraph()で返されるのは、要素数が3つのタプルです。中身は、(文数, 単語数, 1つの段落の文字列)となっています。

Generator()クラスについては、generate_paragraph()以外にもさまざまなメソッドを備えているので、詳しくはLorem Ipsumライブラリの公式ドキュメントをごらんください。


インストール
pipをインストールしてあれば、次のコマンドでインストールできます。
pip install loremipsum

以上です。


参考
loremipsum - pypi
Lorem Ipsum - 公式ドキュメント

2013/08/19

ライブラリ:pprint

Pythonの「 pprint 」というライブラリについてご紹介します。

import pprint 

pprint は、「 pretty-print 」の略で、 Python のオブジェクトを人が読みやすい形に整形して表示してくれるライブラリです。同名の「 pprint 」という関数がそのメインとなります。

とてもシンプルな関数ですが、コーディング途中に値を確認したいときなんかにとても便利です。

インストール


pprint は標準ライブラリに含まれているので、別途インストールする必要はありません。

以下いくつかサンプルを見ていきましょう。

リストの場合


import pprint 

nums = ['one', 'two', 'three']
pprint.pprint(nums)
# 次のとおり表示
# ['one', 'two', 'three']
短いリストなんかは、そのまま print したのと同じ形で表示されます。

sentence = """
Python is a remarkably powerful dynamic programming language
"""
words = sentence.strip().split(' ')
pprint.pprint(words)
# 次のとおり表示
# ['Python',
#  'is',
#  'a',
#  'remarkably',
#  'powerful',
#  'dynamic',
#  'programming',
#  'language']
リストの要素数が多く、横に続けて表示するには長い場合なんかには、縦のラインを揃えて縦に表示してくれます。

辞書の場合


vegies = {'c': ['carrot', 'cucumber'],
          'l': 'lettuce',
          'p': ['potato', 'pepper'],
          't': 'tomato'}
pprint.pprint(vegies)
# 次のとおり表示
# {'c': ['carrot', 'cucumber'],
#  'l': 'lettuce',
#  'p': ['potato', 'pepper'],
#  't': 'tomato'}

辞書型の変数や、入れ子になったオブジェクトなんかも、きれいに整形して表示してくれます。

関数が含まれたリストの場合


import math
mathfuncs = [math.sin, math.cos, math.tan, math.exp]
pprint.pprint(mathfuncs)
# 次のとおり表示
# [<built-in function sin>,
#  <built-in function cos>,
#  <built-in function tan>,
#  <built-in function exp>]

その他クラス名の場合なんかにも、横に長くなるときには自動的に改行してきれいに表示してくれます。

以上です。


参考
pprint - Python公式ドキュメント

ライブラリ:StringIO

Pythonの「StringIO」というライブラリについてご紹介します。

import StringIO

StringIOは、文字列にファイルオブジェクトのインタフェースを与えることができるライブラリです。StringIOを使うと、文字列をファイルオブジェクトのように扱うことができます。

例を見てみましょう。

01 文字列の追加

import StringIO

io = StringIO.StringIO()

io.write('This is the first line.\n')
io.write('This is second.\n')

io.close()
StringIOライブラリを使うには、まずはStringIOインスタンスを生成します。生成したインスタンスのwrite()メソッドに文字列を渡すと、文字列を追加することができます。

これはちょうど、次のようにFileクラスのインスタンスに対してwrite()メソッドを使うことと同じようなイメージになります。
f = open('sample.txt', 'r')

f.write('This is the first line.\n')
f.write('This is second.\n')

f.close()
close()でそのインスタンスを解放できる点もFileオブジェクトと同じです。

f.writelines(['3rd\n', '4th\n', '5th\n'])
write()では引数に文字列を受け取りましたが、writelines()の場合は文字列のリストやタプルを受け取ります。

print >> io, '6th\n'
StringIOインスタンスをprint文の出力先に設定することもできます。

02 文字列の読み出し

sentence = u"""古池や
蛙飛びこむ
水の音
"""

io2 = StringIO.StringIO(sentence)
print io2.getvalue()
io2.close()
# 次のとおり表示
# 古池や
# 蛙飛びこむ
# 水の音
文字列の読み出しには、いくつかのメソッドを使うことができます。getvalue()は、バッファ内の文字列をすべて返してくれるメソッドです。

ほかの読み出し用メソッドとしては、次のようなものがあります。
  • read()
  • readline()
  • readlines()

このあたりのメソッドはFileオブジェクトにあるものと同じ働きをします。それぞれ次のような特徴があります。
  • read() 現在のポインタ(カーソル?)の位置以降の文字列をすべて返す
  • readline() 現在のポインタの位置以降の行を1行返す
  • readlines() 現在のポインタの位置以降の文字列を行ごとに分けてリストで返す

いずれも引数として整数値を渡すとそのバイト分だけの文字列を返す仕様となっていますが、それぞれちょっとずつちがいがあります。詳細は公式ドキュメントのFileオブジェクトのパートをご確認いただくのがよいかと思います。

上で出てきたgetvalue()とこれらとのちがいは、これら3つは現在のポインタの位置によって出力が異なりますが、getvalue()はポインタの位置にかかわらずすべての文字列を返してくる点です。

以上です。


StringIOをたくさん使う場合には、StringIOと同じインタフェースを備えたより高速なcStringIOを使うのがよさそうです。


参考
StringIO - Python公式ドキュメント
Fileクラス - Python公式ドキュメント
python StringIO usage? - Stack Overflow
What is StringIO in python used for in reality? - Stack Overflow

2013/08/15

ライブラリ:virtualenv

Pythonのライブラリ「virtualenv」についてご紹介します。

「virtualenv」は独立したPython環境を手軽に構築できるようにしてくれるツールです。コマンドラインから使うタイプのものとなります。

たとえば
  • 複数のPython環境を作って、手軽に切り替えて使いたいとき
  • 一時的に利用する使い捨ての環境を作りたいとき
なんかに便利です。

具体的には、「Pythonを動かすのに必要なセットを任意のディレクトリに作る」ということをコマンドひとつでやってくれます。

一度馴染めば、使うコマンド・オプションはごくわずかだしシンプルなツールなのですが、一見、ちょっとややこしいものに見えるかもしれません。

以下、ざっとシンプルに、使い方を見ていきたいと思います。まずはインストールから。

virtualenvのインストール

pipが入っていれば、コマンドから次のように打てば入ってくれます。
pip install virtualenv

コマンドラインから次のように入力してヘルプが表示されればインストールは成功です。
virtualenv

インストールは確かにできているのにvirtualenvコマンドが使えない、といった場合にはパスが通っていない可能性が高いので、Windowsの場合はPythonディレクトリ内の「Scripts」にパスを通しましょう。

pipやeasy_installが入っていない、あるいは使えない、といった場合には、pypiのvirtualenvのページからtar.gz一式をダウンロードしてきましょう。その中にある「virtualenv.py」を取り出してこれば、これ単体で使うことが可能です(レンタルサーバなんかで使う場合はこちらになるかと思います)。

独立環境の作成

実際にvirtualenvを使ってみましょう。適当なディレクトリに行き、次のコマンドを実行します。
virtualenv myenv

すると、カレントディレクトリに「myenv」というディレクトリが作られ、その中にPython環境一式が入れられます。「myenv」の部分は任意の名前を入力します。

上述の「virtualenv.pyを単体で使う場合」では、次のようにするとよいかと思います。
python virtualenv.py myenv

独立環境の利用

つづいて、作成した独立環境を利用する方法についてです。まずは独立環境のディレクトリに移動します。
cd myenv

次に、独立環境に切り替えます。Linuxなら次のように、
source bin/activate
Windowsなら次のようにコマンド入力します。
Scripts\activate

シェル(コマンドプロンプト)の先頭が
(myenv) ...
に切り替わったら、無事その環境に入れた証拠です。

この状態でPythonスクリプトをコマンドラインから実行すると、作成した環境の中で走らせることができます。

Linux系の環境の場合は、シバン(Shebang)で独立環境のpython.exeを指定すると、都度都度コマンドを打たなくても、その環境を使うことが可能です。

which python
もしwhichコマンドが使えるなら、whichコマンドで確認してみるのもよいかと思います。独立環境内のpython.exeが呼ばれていることが確かめられます。

独立環境から元に戻る

独立環境からぬけるには、コマンドで次のように打ち込みます。
deactivate

独立環境でのpipの利用

virtualenvが特に有効なのは、pipなどを使ってライブラリ・パッケージを出し入れするときかと思います。

virtualenvでは、setuptoolsとpipとが自動でインストールされるので、最初から使うことができます。ただ、setuptoolsは更新が止まっているので、setuptoolsに代わるdistributeを使うのがよいかと思います。setuptoolsの代わりにdistributeを入れるには、virtualenvコマンドに「--distribute」オプションをつけます。
virtualenv --distribute myenv2 && cd myenv2

あとは「Scripts\activate」で環境を切り替えてから「pip freeze」とすると、その環境の中のパッケージ一覧を確認することができます。
Scripts\activate
pip freeze

他のPCと環境を合わせたいときなんかには、コピー元の環境で
pip freeze > packages.txt
としてパッケージ一覧を作成しておき、コピー先で次のようにすると、同じパッケージ群をまとめてインストールすることができます。
pip install -r packages.txt

独立環境の削除

使い終わって用がなくなったら、最初にvirtualenvで作られたディレクトリごと削除すれば完了です。ここも、かんたん・便利です。


以上です。

virtualenvの使い勝手をさらによくするvirtualenvwrappervirtualenv-burritoといったツールなんかもあるようです。これらはWindowsではすぐには使えなかったり、私の場合はvirtualenvで間に合っていたりするので私は使っていませんが、virtualenvを使いたおすような方はこれらの利用も検討してみるとよいかもしれません。


参考
virtualenv - PyPI
2009年版Python開発環境を整えよう
1分でpython環境を整える方法 - mojavy.com

2013/08/06

ライブラリ:pip

Pythonの「pip」というライブラリ(パッケージ?)についてご紹介します。

pipは、いわゆる「パッケージ管理ツール」。Pythonのライブラリを手軽にインストールしたり管理したりすることができます。メインに使うのは、コマンドラインから使う「pip」コマンドです。

ブラウザなどを使わずにコマンドラインだけでパッケージをインストールしたりできるので、位置づけとしては、Rubyでいうところの「gem」、Linuxの「apt-get」「yum」「rpm」コマンドに近いイメージかなと思います。

以下、使い方を見ていきます。

01 pipそのもののインストール

pipを使うには、「setuptools」「distribute」のどちらかが必要です。

まずはそのどちらかをインストールし、コマンドラインから「easy_install」コマンドが使える状態にしておきます(setuptoolsは更新が止まっているようなので、今ならdistributeの方がおすすめです)。

その状態のもとで次のように打ち込むと、pipをインストールすることができます。
easy_install pip

02 pipを使ったパッケージのインストール

以下、pipを実際に使っていきます。

pip install virtualenv
パッケージをインストールするには、「pip install」を使います。「pip install」に続けてパッケージ名を入れると、pipが該当するパッケージを探してきて、ダウンロード・インストールしてくれます。依存しているパッケージがある場合は、依存関係を調べてあわせてインストールしてくれます。

パッケージ名の照合には、デフォルトでPyPIのパッケージ名一覧ページを使用するようです。

パッケージ名ではなく、URLを指定してインストールすることも可能です。オプションなどは必要なく、パッケージ名の部分にURLをそのまま打ち込みます。
pip install https://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.8.4.tar.gz

使う機会はあまり多くはないかと思うのですが(私は使ったことがありません)、依存パッケージをインストールしない設定にしたり、パッケージ名の照合ページを変更したりすることなんかも可能です。

依存したパッケージを入れないなら。
pip install --no-deps virtualenv

パッケージ名の照合先のページを変更したいなら。
pip install --index-url=URL virtualenv

また、easy_installとpipをごちゃまぜで使っていると、easy_installで入れたパッケージがpipでは管理対象外となるなどするようですので、もしpipを使うのであればeasy_installは使わずpip一本に統一した方がよいようです。

03 インストール済みパッケージの確認

pip freeze
インストールされたパッケージを確認したいときは「pip freeze」を使います。各パッケージがパッケージ名とバージョンとをセットにして一覧表示されます。Rubyでいうところの「gem list」ですね。

04 インストールされたパッケージのアンインストール

pip uninstall virtualenv
過去にインストールしたパッケージをアンインストールしたい場合は、「pip uninstall パッケージ名」でできます。

05 パッケージのアップデート

pip install --upgrade virtualenv
パッケージのバージョンを更新するには「pip install」コマンドに「--upgrade」オプションを追加します。すでにpipでインストールできる最新のものが入っている場合はバージョン番号とメッセージが表示されて終了します。

06 おまけ

使い方を忘れてしまったときなんかにはヘルプを覗いてみるとよいかと思います。
pip help

また、複数のマシンに同じPython環境を入れたい場合、virtualenvでいつもお決まりのパッケージを入れている場合なんかには、一括インストール機能が便利です。

pip freeze > packages.txt
pip freezeで出力したパッケージ一覧を「-r」オプションをつけて「pip install」に渡すと、複数のパッケージの一括インストールが可能です。
pip install -r packages.txt

回数が増えてくると、ものすごく重宝します。

また、注意したい点としては、Windowsの場合は、pipではなく実行形式のインストーラ(.exe)を使ってインストールした方がよいものもあるため、実行形式のインストーラがあるかどうかは一度少し調べてから使うのがよいかと思います。

私に馴染んでいるものでいうと、
  • numpy
  • scipy
  • matplotlib
  • iPython
  • PIL
あたりのライブラリは、pipではなくインストーラを使った方がよいようです。

以上です。


私は長年Windowsばかり使ってきたため、pipのようなCUIベースのパッケージ管理ツールにはあまり馴染みがなかったのですが、一度慣れると、ものすごく便利で、、これはもう元には戻れない感じがします。。素晴らしいです。


参考
pip - PyPI
PyPI パッケージ名一覧
PIP公式ドキュメント
pipの使い方 - そこはかとなく書くよ。

2013/08/02

Python 2 の print 文の使い方

Python2 の print 文についてご紹介します。

print '文字列'

Python3 からは print は関数として位置づけられています。 Python3 の print() 関数の使い方については次のページなどが参考になるかと思います。

Python 3 の print() 関数の使い方

Python2 で「文字列出力」といえば print 文です。このページでは Python2 系における print 文の使い方を見てみましょう。

基本

s1 = 'world'
print "Hello"  # helloと表示
print s1  # worldと表示
最もベーシックな使い方は「 print 表示したい文字列」です。

print 文を普通に使うと、文字列の末尾で自動的に改行されます。 Ruby の puts に近いイメージでしょうか。'(シンルグクォーテーション)と"(ダブルクォーテーション)にちがいはありません。

複数の引数

s1 = 'tonari no'
s2 = 'kyaku ha'
s3 = 'yoku kaki ku'
print s1, s2  # tonari no kyaku ha yoku kaki kuと表示
print 文の場合「引数」と呼んでよいのかわかりませんが、引数を複数渡したい場合は「,」で区切ってつなげます。結果は、与えられた結果が半角スペースでつなげられたものとなります。

フォーマット指定

n1 = 1.414

print '%d' % n1  # 1
print '%f' % n1  # 1.414000
print '%0.1f' % n1  # 1.4
フォーマット指定は、「print フォーマット % 変数」という形で行います。

s1 = 'Hello'
s2 = 'world'

print '%s, %s' % (s1, s2)  # Hello, worldと表示
変数をひとつだけでなく複数個渡したい場合は、タプルを使います。

s1 = 'Hello'
s2 = 'world'

print '%(str1)s, %(str2)s' % \
        { 'str1': s1, 'str2': s2}
タプルではなく、辞書を渡して表示することもできます。この場合は、「%(キー名)フォーマット」という形でフォーマットを指定します。

たくさんの変数が渡したいとき、辞書の中身をフォーマットして表示したい場合なんかに便利です。

改行なし

print 'Hello',
print 'world'
# Hello worldと表示
print 文を通常のやり方で使うと末尾に改行が自動で追加されてしまいます。これを避けるには、 print 文の最後に,(コンマ)を追加します。

この例では、 Hello のあとの改行が半角スペースに変換されて表示されています。

import sys

sys.stdout.write('Hello')
sys.stdout.write('world')
# Helloworldと表示
「 print 文字列,」という形だと改行の代わりに半角スペースがひとつ入ってしまうのですが、改行も半角スペースも入れたくない場合には、
sys.stdout.write() という関数を使います。

ちなみに、 print 文は内部的にはこの sys.stdout のラッパだそうです。

標準出力以外に出力

f = open('sample.txt', 'w')
print >> f, 'ABC EFG HIJ'
f.close()
# ファイルsamle.txtに文字列ABC EFG HIJが書き込まれる
出力先を標準出力から別のものに変えたい場合は、「 print >> 出力先, 文字列」という形を使います。


その他

その他、特殊文字のエスケープやフォーマット指定子については、他の言語とよく似ているので、ここでは割愛します。

詳細は公式ドキュメントの print 文の箇所文字列フォーマットの箇所をごらんいただくとよいかと思います。

以上です。

繰り返しになりますが、ここで挙げた print 文は python2.* 系でのお話で、 python3 には適用できませんのでご注意ください。

Python 3 の print() 関数の使い方


参考
print 文 - Python 公式ドキュメント
string formatting operations - Python公式ドキュメント
Python - The difference between sys.stdout.write and print - Stack Overflow
Redirect stdout to a file in Python? - Stack Overflow
sys.stdout - Python公式ドキュメント

2013/07/29

Python Tips:Pythonのイースターエッグ

Pythonのイースターエッグについてご紹介します。

・・・の説明の前に、まずは「イースターエッグ」について。イースターエッグとは、開発者の遊び心で作られた隠し機能のことです。Wikipediaのページでは次のように説明されています。

イースター・エッグ(Easter egg)とは、コンピュータのソフトウェア・書籍・CDなどに隠されていて、本来の機能・目的とは無関係であるメッセージや画面の総称である。ユーモアの一種である。
これらを「イースター・エッグ」と呼ぶのは、キリスト教の復活祭の際に、装飾した卵(イースター・エッグ)をあちこちに隠して子供たちに探させる遊びにちなむ。
個人的には、もともとの卵を探す遊びの方を知らないので、イースターエッグといえばこちらのイースターエッグが思い浮かびます。

Pythonにもイースターエッグが存在するようです。以下、いくつか見ていきます(これから知る方にとってネタバレにならないよう、やり方だけ・・・)。

import this

import this
# 以下のとおり表示
# The Zen of Python, by Tim Peters
# 
# Beautiful is better than ugly.
# Explicit is better than implicit.
# ...
「import this」とやると、「The Zen of Python」(禅オブPython)がズラズラーっと表示されます。

import hello

import __hello__
import __phello__
プログラマの最初の一歩といえば「Hello world」ですよね。なぜ、「phello」でもHello worldなのかわかりませんが、、「print hello = phello」、でしょうか。

from __future__ import braces

from __future__ import braces
これはPythonのインデント構文にまつわるイースターエッグです。

他の言語でよくある {} ーーいわゆる braces を使ったブロック表現を import します、という意味の import 文。結果は「ありえないっす!」的なニュアンスでしょうか。「インデントによるブロックがこんなにイケてるのに {} なんて導入するわけないじゃん!」的な感じなのかな。

import antigravity

import antigravity
これは、やってみてのお楽しみ。antigravityは「反重力」的な意味です。

love is...

最後に、これはイースターエッグではないのですが、Pythonインタプリタを使ったことば遊びとしてPythonメーリングリスト上で紹介されたそうです。

>>> import this
...
>>> love = this
>>> this is love
True
>>> love is True
False
>>> love is False
False
>>> love is not True or False
True
>>> love is not True or False; love is love
True
True

以上です。


参考
Easter eggs in Python

2013/07/22

ライブラリ:timeit

Pythonの「timeit」というライブラリについてご紹介します。

import timeit

「timeit」は実行時間を計測するためのライブラリです。

スクリプト内で使うこともコマンドラインからも使うこともできます。以下、順に見ていきます。

スクリプト内で

import timeit

# Timerインスタンスを生成
# Timer(時間を計測したい処理, 前処理)
t = timeit.Timer("math.sin(10)", "import math")

# 時間を実際に計測
print t.timeit() # 0.45...など
時間を計測するには、Timerクラスのインスタンスを生成した後timeit()メソッドを実行すれば行うことができます。

Timerクラスを生成するときは、「時間を計測したい処理」と、その最初に実行したい「前処理」を与えます。デフォルトでは100万回実行されたときの合計時間が返ってきます。

時間の単位は現実世界の秒やマイクロ秒(wall clock time)などで、CPU時間(CPU time)ではありません。

print t.timeit(1000)
timeit()に整数を渡すと、実行回数を変更することもできます。この場合は1000回の繰り返しとなります。

print min(t.repeat(5))
repeat()は、timeitによる計測をn回連続で行い、結果を長さnのリストに格納して返してくれます。この場合は長さ5のリストが返ってきます。

timeit()が返す数値は他の実行中のプロセスなどによって変わったりもするため、複数回試した場合は、その平均値よりも最小値(min)を見ておくのがよいそうです。

the min() of the result is probably the only number you should be interested in.

つづいて、コマンドライン上での使い方について。

コマンドラインから

$python -m timeit "[str(x) for x in range(100)]"
10000 loops, best of 3: 63.7 usec per loop
コマンドラインから使う場合は、「python -m timeit」のあとにオプションをつけて使います。デフォルトでは、3回実行したうちの最小の時間が帰ってきます。

python -m timeit -n 10 -r 5 -s "import math" "[math.sin(x) for x in range(1000)]"
オプション「n」で1試行あたりの実行回数、「r」で試行回数、「s」で前処理を指定することができます。この場合であれば、処理を10回連続で実行したときの時間を5回計測し、そのうちの最短の時間を返してくれます。

ほかにもオプションがありますので、詳しくは公式ドキュメントをご参照ください。

以上です。


参考
timeit - Python公式ドキュメント
How to use timeit correctly - stackverflow
timeit – 小さな Python コードの実行時間を計る - Python Module of the Week

2013/07/20

ライブラリ:calendar

Pythonの「calendar」というライブラリについてご紹介します。

import calendar

「calendar」は、名前のとおりカレンダー情報を扱うためのライブラリです。中身はとてもシンプルで、「何年何月」という形で特定の月を指定すればその月の日・曜日情報を返す、といった機能がメインです。

もっと広い範囲で日付や時間の情報を扱いたい場合は「datetime」や「time」といったライブラリが便利です。

以下、主な機能を見ていきます。

month()

imort calendar

print calendar.month(2013, 8)
# 次のとおり表示される
#     August 2013
# Mo Tu We Th Fr Sa Su
#           1  2  3  4
#  5  6  7  8  9 10 11
# 12 13 14 15 16 17 18
# 19 20 21 22 23 24 25
# 26 27 28 29 30 31
month()は、年と月を整数で渡せば、その月のカレンダーを文字列として返してくれる関数です。

print type(calendar.month(2013, 8)).__name__
# strと表示される
返ってくる中身は通常の文字列です。

Calendar

c1 = calendar.Calendar()

print type(c1).__name__  # Calendar
カレンダーをひとつ表示するだけであればmonth()で十分ですが、ちょっと複雑な(といってもシンプルですが)カレンダー情報を扱うのであればCalendarクラスを利用するのが便利です。

for ele in c1.iterweekdays():
    print ele,
# 0 1 2 3 4 5 6 と表示される
インスタンスメソッドiterweekdays()は、曜日を表す0から6の数字を生成してくれるイテレータです。0が月曜日、6が日曜日に対応しています。

c2 = calendar.Calendar(firstweekday=5)
for ele in c2.iterweekdays():
    print ele,
# 5 6 0 1 2 3 4 と表示される
始まりの曜日はデフォルトでは月曜日となっていますが、変えたい場合はオプションfirstweekdayが利用できます。

for ele in c1.itermonthdays2(2013, 8):
    print '(%2d,%2d)' % (ele[0], ele[1]),
    if ele[1] == 6:
        print
# 次のとおり表示される
# ( 0, 0) ( 0, 1) ( 0, 2) ( 1, 3) ( 2, 4) ( 3, 5) ( 4, 6)
# ( 5, 0) ( 6, 1) ( 7, 2) ( 8, 3) ( 9, 4) (10, 5) (11, 6)
# (12, 0) (13, 1) (14, 2) (15, 3) (16, 4) (17, 5) (18, 6)
# (19, 0) (20, 1) (21, 2) (22, 3) (23, 4) (24, 5) (25, 6)
# (26, 0) (27, 1) (28, 2) (29, 3) (30, 4) (31, 5) ( 0, 6)
itermonthdays2()は、年・月を渡すとその月のすべての(日, 曜日)を返してくれるメソッドです。

その月の「最初の日を含む週の最初の日」から「最後の日を含む週の最後の日」までの日付が返ってくるため、要素数は必ず7の倍数です。また、その月に属さない日の日付部分はすべて0となります。

名前に「2」のつかないitermonthdays()というメソッドもあって、こちらは曜日情報を含まない日付の部分のみをリストで返します。

for ele in c1.itermonthdates(2013, 8):
    print ele
# 次のとおり表示される
# 2013-07-29
# 2013-07-30
# 2013-07-31
# 2013-08-01
# 2013-08-02
# ...
# 2013-08-31
# 2013-09-01
# print type(ele).__name__  # datetime.date
itermonthdays2()は各要素を(日, 曜日)というフォーマットで返しましたが、itermonthdates()は各要素をdatetimeライブラリのdatetime.date型のインスタンスとして返します。

c3 = c1.monthdays2calendar(2013, 8)
for week in c3:
    print week
# 次のとおり表示される
# [(0, 0), (0, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 6)]
# [(5, 0), (6, 1), (7, 2), (8, 3), (9, 4), (10, 5), (11, 6)]
# [(12, 0), (13, 1), (14, 2), (15, 3), (16, 4), (17, 5), (18, 6)]
# [(19, 0), (20, 1), (21, 2), (22, 3), (23, 4), (24, 5), (25, 6)]
# [(26, 0), (27, 1), (28, 2), (29, 3), (30, 4), (31, 5), (0, 6)]
itermonthdays2()はすべての日付をフラットに返しましたが、monthdays2calendar()は、itermonthdays2()が返す要素を週単位に分けて返してくれます。

c4 = c1.monthdatescalendar(2013, 8)
print len(c4)  # 5
print c4[0][0]  # 2013-07-29
monthdays2calendar()と同様に、datetime.dateを週単位にまとめて返してくれるmonthdatescalendar()というメソッドもあります。週単位にまとめるのでlen(c4)は5(5週)となっています。

メインとなるのはこのCalendarクラスですが、その他にも、カレンダーを表示することに特化したTextCalendar、HTMLCalendarというクラスが用意されています。

TextCalendar

c5 = calendar.TextCalendar()
print c5.formatmonth(2013, 8, w=3)
print c5.formatyear(2013)
TextCalendarは、カレンダー情報をテキストとして出力するためのクラスです。formatmonth()は月単位、formatyear()は年単位で次のような整形されたカレンダーを出力することができます。

#         August 2013
# Mon Tue Wed Thu Fri Sat Sun
#               1   2   3   4
#   5   6   7   8   9  10  11
#  12  13  14  15  16  17  18
#  19  20  21  22  23  24  25
#  26  27  28  29  30  31

HTMLCalendar

TextCalendarがプレーンテキストに表示するのに対し、HTMLカレンダーは、タグ付きのHTMLフォーマットのカレンダーを出力します。
FILEOUT = 'sample_calendar.html'

c3 = calendar.HTMLCalendar()

f = open(FILEOUT, 'w')
f.write(c3.formatmonth(2013, 8))
f.close()

以上です。


参考
calendar - Python公式ドキュメント
Python Date & Time - tutorialpoint

2013/07/18

ライブラリ:time

Pythonの「time」というライブラリについてご紹介します。

import time

「time」は、時間関連の情報や関数を集めたライブラリです。もちろん用途によって変わってはくるかと思うのですが、頻度の高い使いどころとしては次のようなものがあるでしょうか。
  • システムの現在時刻を取得する
  • 時刻形式のデータを生成する
  • 時刻のフォーマットを変更する
  • スリープ

以下、順番に見ていきます。

・・・の前にひとつ前置きを。

以下、epoch(エポック)ということばが出てきますが、これは「原点となる時点」を表すことばとして使っています。たとえば、西暦であれば西暦0年1月1日の0時がエポックですし、平成であれば平成元年1月1日の0時がエポックといえます。Unixの世界では、これが1970年の1月1日0時に設定されており、そこからの経過秒数がベースとなっています。公式ドキュメントにも説明が載っています

それでは以下、順番に。

システムの現在時刻を取得する

print time.time()  # epochからの秒数を返します
epochからの時間を秒数で得るにはtime()を使います。

print time.gmtime()
# 現在のUTC(元グリニッジ標準時)を
# time.struct_timeオブジェクトとして返します
人間にとってわかりやすい年・月・日という形式の時刻情報を取得するには、gmtime()を使います。これは、time.struct_timeという形式で現在時刻を返してくれます。

print time.gmtime().tm_year  # 2013 現在の年を4桁で返します
struct_timeは年・月・日・時・分・秒などの情報をアトリビュートとして持ったオブジェクトです。年・月・日など以外にも、曜日、その年の頭から数えての経過日数、サマータイムに関するフラグなどの情報も持っています。それぞれ名前は次のとおりとなっています。
  • tm_year 年
  • tm_mon 月
  • tm_mday 日
  • tm_hour 時
  • tm_min 分
  • tm_sec 秒
  • tm_wday 曜日を0~6で表した数値
  • tm_yday 年の頭から数えた経過日数
  • tm_isdst サマータイムのフラグ
公式ドキュメントの該当するパートもよろしければごらんください。

print time.localtime()
# 設定されたタイムゾーンにおける現在の時刻を返します
# gmtime()と同じく、time.struct_time形式で返します

時刻形式のデータを生成する

print time.struct_time([2013, 1, 1, 1, 10, 15, 1, 1, 0])
# time.struct_time([tm_year=2013, tm_mon=1, tm_mday=1, tm_hour=1, tm_min=10, tm_sec=15, tm_wday=1, tm_yday=1, tm_isdst=0])
時刻形式形式のデータを生成するには、time.struct_timeに時刻情報が入ったリストを渡します。時刻情報は、上述の年・月・日などの9つの情報となります。

時刻のフォーマットを変更する

t = time.localtime()
print time.mktime(t)  # epochからの秒数
struct_time形式の時刻を「epochからの秒数」に変換するには、mktime()を使います。1秒以下の精度でも時間を計測することができます。

sec = time.time()
print time.gmtime(sec)  #  UTCでの時間
print time.localtime(sec)  #  ローカルのタイムゾーンでの時間
逆に、「epochからの秒数」を年・月・日・・・形式に変換するには、gmtime()、localtime()に引数を与えて使います。

t = time.localtime()
print time.strftime("year:%Y week:%W", t)
# year:2013 week:30 などと返されます
struct_time形式の時間をフォーマット指定で文字列に変換するには、strftime()を使います。

tstr = "2013 08 01"
print time. strptime(tstr, "%Y %m %d")
# time.struct_time(tm_year=2013, tm_mon=8, ...
文字列を読み取ってstruct_time形式に変換するには、strptime()を使います。引数のひとつめに文字列を、ふたつめにフォーマットを渡します。

strftime()とstrptime()のフォーマットにおける規則はこちらに一覧が載っています。
http://docs.python.org/2/library/time.html#time.strftime

スリープ

time.sleep(3.5)  # 3.5秒停止
Pythonプロセスの実行を一定時間停止するには、sleep()を使います。引数の単位は「秒」です。



インストール
timeはPython本体をインストールすれば最初から入っているため、別途インストールは必要ありません。


参考
time - Python公式ドキュメント

2013/07/06

ライブラリ:datetime

Pythonの「datetime」というライブラリについてご紹介します。

import datetime

「datetime」は、時間に関するデータを取り扱うためのライブラリです。Pythonの標準モジュールとしてPythonに同梱されています。

時間情報を扱う同様のライブラリとして「time」「calendar」などがあります。timeとdatetimeはよく似ているのですが、datetimeは

  • よりシンプル
  • 日付の部分と時間の部分を分けられる
  • 時刻の差分(日付 - 日付)が手軽に取り扱える

などのポイントがtimeと異なる点かと思います。

以下、おもな機能を見てみます。

datetimeのデータ型

import datetime

print datetime.datetime.__name__  # datetime
print datetime.date.__name__  # date
print datetime.time.__name__  # time
datetimeには、datetime、date、timeという3つのタイプのデータ型があります。名前のとおり、datetimeは日付と時刻をまとめた時間、dateは日付のみ、timeは時刻のみを扱うオブジェクトです。

print datetime.timedelta.__name__  # timedelta
また、日付間、時刻間の差分を表す型として、timedeltaというものが用意されています。

datetime

datetimeは、年、月、日、時間、分、秒、マイクロ秒(100万分の1秒)という情報を持ったデータ型です。
t1 = datetime.datetime(2013,8, 5, 3 ,50 ,25)
t2 = datetime.datetime.today()

print t1  # 2013-08-05 03:50:25 と表示される
print t2  # t1と同じフォーマットで現在時刻が表示される
datetime(年, 月, 日, ...)という形式でインスタンスを作ることができます。メソッドtoday()を使うと、現在の日・時を得ることができます。

import time
t3 = datetime.datetime.fromtimestamp(time.time())
print t3  # t1と同じフォーマットで現在時刻が表示される
fromtimestamp()というメソッドを使えば、time.time()が返すような、1970年1月1日0時からの経過秒数で表された時刻フォーマット(POSIXタイム)をdatetime形式に変換することができます。

t4 = datetime.datetime.strptime('2013 08 05', '%Y %m %d')
print t4  # 2013-08-05 00:00:00 と表示される
文字列で表された時刻をdatetime型に変換するには、strptime()を使います。

年や月などの情報にアクセスするには、アトリビュートやメソッドを使います。
print t2.year  # 年
print t2.month  # 月
print t2.day  # 日
print t2.hour  # 時
print t2.minute  # 分
print t2.second  # 秒
print t2.microsecond  # マイクロ秒
print t2.weekday()  # 曜日を表す0から6の数字

「-」演算子を使うことで、2時刻間の差分も簡単に得ることができます。
d1 = t1 - t2
print type(d1).__name__  # timedelta
print d1  # 32 days, 15:25:33.... などと表示される
差分を取ることで、timedeltaインスタンスが自動的に生成されます。

datetime型の変数に「+」「-」演算子でtimedeltaを加えることで、元の日付にその差分を加えた日付を得ることも可能です。
d2 = datetime.timedelta(days=350)
t3 = t1 + d2
print type(t3).__name__  # datetime
print t3  # t1にd2を追加した時間が表示される

date

t5 = datetime.date(2013, 10, 12)
t6 = datetime.date.today()

print t5  # 2013-10-12
print t5  # t5と同じフォーマットで本日の日付
dateは、日付部分――年・月・日の情報のみを持ったデータ型です。ちょうど、datetimeが持つパラメータや機能のうち時刻の部分を取っ払って日付に関する部分だけを抽出したような内容となっています。

データとしては日付部分だけしか見なくてdatetimeは冗長だ、といった場合なんかには便利かと思います。

time

t7 = datetime.time(7, 5 ,37)
print t7
dateとは逆に、日付部分を取っ払い、1日のうちの時刻の部分――時・分・秒・マイクロ秒のみを持ったデータ型がtimeです。

timeはdatetime、timeと比べて機能がシンプルで、today()やnow()なども用意されていないようです。

以上です。

ほかにも、タイムゾーンを表現する「tzinfo」や「timezone」といったオブジェクト、フォーマットの変換機能なんかも用意されていておもしろいので、詳しくは公式ドキュメントをごらんになってください。


インストール
「datetime」は標準モジュールとしてPythonに同梱されているので、別途インストールの必要はありません。


参考
datetime - Python公式ドキュメント
datetime - Doug Hellmann
日付の処理いろいろ - GeSource

2013/06/30

ライブラリ:PyYAML

Pythonの「PyYAML」というライブラリについてご紹介します。

import yaml

「PyYAML」(ライブラリとしてimportするときは「yaml」)は、YAML形式のデータを扱うためのライブラリです。

YAMLはXMLやJSONと比べるとシンプルなので自分の手でparseするのでもさほど大変ではないかとは思いますが、やはり、ライブラリを使うのが早くて確実かと思います。

PyYAMLには大きく2つの機能――読み込みと書き込みとがあります。以下、順に見ていきます。

YAMLデータの読み込み

import yaml

FILEIN_DICT = "sample_dict.yaml"

f = open(FILEIN_DICT, 'r')
data = yaml.load(f)  # 読み込む
f.close()
YAML形式のデータを読み込むには、yaml.load()を使います。引数には、読み込みモードで開いたファイルオブジェクトを渡します。

以下、「sample_dict.yaml」の中身が次のとおりだと仮定して見てみます。
# dict
name: Takeda Shingen
sex: male
class: Daimyo
region: Kai
year: [1521, 1573]
nickname:
- Kazchiyo
- Kai no tora
YAMLに馴染みがなくてYAMLの文法がよくわからない、という方は、公式サイト(この投稿を書いている時点での最新版は1.2です)Wikipediaのページを参照いただくとよいかと思います。

print type(data).__name__  # dict
トップの階層がハッシュ形式となっているデータを読み込んだときは、load()で生成されるのは辞書型の変数です。

import pprint
pprint.pprint(data)
# 次のとおり出力される
# {'class': 'Daimyo',
#  'name': 'Takeda Shingen',
#  'nickname': ['Kazchiyo', 'Kai no tora'],
#  'region': 'Kai',
#  'sex': 'male',
#  'year': [1521, 1573]}
中身は通常の辞書型のデータになっています。バリューにリストがある場合は、それもPythonのリストとして格納されます。

ここでpprint.pprint()というのを使っていますが、これは変数の中身を整形して表示するためのもので、yamlとは関係ありません(pprintも使うにはインストールが必要です)。

次に、トップの階層がリストになっているデータの場合を見てみます。こちらも基本的にはハッシュと同じです。
FILEIN_DICT = "sample_list.yaml"

f = open(FILEIN_LIST, 'r')
data = yaml.load(f)  # 読み込む
f.close()

「sample_list.yaml」の中身は次のとおりとします。
# list
- C
- Java
- Python
- Ruby
- name: Japanese
  region: Japan
- {name: Kagoshima-ben, region: Kagoshima}

print type(data).__name__  # list
こちらはリストに格納されます。

import pprint
pprint.pprint(data)
# 次のとおり表示
# ['C',
#  'Java',
#  'Python',
#  'Ruby',
#  {'name': 'Japanese', 'region': 'Japan'},
#  {'name': 'Kagoshima-ben', 'region': 'Kagoshima'}]
ハッシュ型と同じく、ノードとしてリストやハッシュを含む場合は、それら子孫ノードもリストや辞書として格納してくれます。

続いて、書き込みの方を。書き込みといっても、文字列に展開する機能だけです。

YAMLデータの書き込み

mylist = {'dogs': ['pochi', 'taro', 'kai'],
          'cats': ['shimajiro', 'tyson']}

f = open('out.yaml', 'w')
f.write(yaml.dump(mylist))  # 書き込む
f.close()
書き込みは、yaml.dump()で行います。dumpで生成されるのは文字列なため、ファイルに書き込む場合は別途ファイルオブジェクトを用意して書き込みます。

最後のもうひとつ、型について少しだけ見てみます。

型の指定

YAMLでは「!!int」といった「タグ」を各ノードの付ける(付記する)ことによって、型の指定ができるようです。私自身使ったことはないのですが、たとえば
  • YAML Python
  • !!null None
  • !!float float
  • !!set set
といったように、YAMLでのタグとPython型との間で対応しているそうなので、型をしっかり見て使う場合なんかには公式ドキュメントの該当するパートをごらんいただくのがよいかと思います。

以上です。


インストール
「pip」が入っていれば、「pip install pyyaml」でインストールすることができます。


参考
PyYAML - PyPI
PyYAMLDocumentation - PyYAML
python - Best way to parse a YAML file - Stack Overflow
YAML - ウィキペディア

2013/06/26

ライブラリ:simplejson

Pythonの「simplejson」というライブラリについてご紹介します。

import simplejson

「simplejson」は、JSON形式のファイルをPythonで手軽に扱うためのライブラリです。Python 2.6から標準ライブラリに組み込まれた「json」ライブラリは、このsimplejsonと同じ内容になっています。

「simlejson」と「json」とでは使える関数なんかも全く同じで、ちがうのは、simplejsonの方が頻繁にアップデートされている点。simplejsonの方は、関数のオプション引数が追加されていたり、パフォーマンスが改善されていたりするそうです。

Pythonを普通に使う分にはjsonでよいかと思うのですが、実行速度が気になる状況や新しい機能を利用したい場合なんかにはsimplejsonを導入するのがよいかと思います。

stack overflowにjsonとsimplejsonのちがいについての質問・回答なんかもありますのでよろしければそちらもどうぞ。

基本的な使い方はjsonとまったくいっしょなので、詳しくはjsonの投稿をご覧ください。


参考
simplejson - PyPI
simplejson — simplejson documentation
simplejson - github
`json` and `simplejson` module differences in Python - Stack Overflow

2013/06/18

ライブラリ:json

Pythonの「json」というライブラリについてご紹介します。

import json

「json」は、その名のとおり、JSON形式のファイルをPythonで扱うためのライブラリです。

jsonライブラリの魅力は、何といってもシンプルな点です。「ElementTree」などに見られるような高度な機能は備えていませんが、本当にシンプルなのですぐに使いはじめることができます。

以下、使い方を見ていきます。

JSONで主に使う機能は次の2つです。
  1. json.load(f)
  2. json.dump(obj, f)

前者のload()はJSONファイルからデータを読み込むときに、dump()はJSONファイルへとデータを書き込むときに使用します。まずは読み込みについて、次に書き込みについて見ていきます。

JSONファイルの読み込み

import json

FILEIN = 'sample_in.json'

f = open(FILEIN, 'r')
data = json.load(f)
f.close()
open()で生成したファイルオブジェクトをload()関数に渡すことで、JSONファイルを読むことができます。

以下、sample_in.jsonには以下のような内容が入っているものとして見ていきます。
{
    "version": "1.0",
    "encoding": "UTF-8",
    "feed": {
        "title": {
            "type": "text",
            "$t": "Life with Python"
        },
        "entry": [{
        },{
            # エントリ1の中身
        },{
            # エントリ2の中身
        }]
    }
}

print type(data).__name__  # dict
load()で生成されるのは、通常の辞書型のオブジェクトです。ですので、いったん読み込んだら、あとはもう通常の辞書型のデータとして扱うことができます。
print data['version']  # 1.0
print data['encoding']  # UTF-8
for k in data:
    print k
# 以下のとおり表示
# feed
# version
# encoding
print data['feed']['title']['$t']
# Life with Pythonと表示
下の階層のデータを取得するには、このようにひとつずつ掘り下げていきます。このあたりもシンプルで、ElementTreeなどにあるような便利な機能はありません。

つづいて保存について。

JSONファイルへの書き込み

FILEOUT = 'sample_out.json'

f = open(FILEOUT, 'w')
json.dump(data, f)
f.close()
ファイルに書き込むときに使うのは、dump()です。引数は最小で2つあり、ひとつめに書き込みたいオブジェクトを、ふたつめに書き込みモードで開いたファイルオブジェクトを渡します。

ここでは辞書型のデータについて見てみましたが、そのほかの形式については次のように対応しています。

対応関係

JSONの各型は右のPythonの各型に対応しています。
  • object: dict
  • array: list
  • string: unicode
  • int: int, long
  • real: float
  • true: True
  • false: False
  • null: None
JSONでのobjectはPythonのdict型に、arrayはlist型に対応しています。load()のときはJSON→Python、つまり左から右に、dump()のときは逆で右から左に変換するイメージです。TrueやFalseなんかもうまく変換してくれるようです。

詳しくは公式ドキュメントのEncoders and Decodersのパートを参照されるとよいかと思います。

今回取り上げたload()、dump()はファイルを対象とした関数ですが、文字列を対象とした関数も用意されています。load()、dump()に対応するのが、それぞれの末尾にsをつけた
  1. loads(string)
  2. dumps(obj)
です。使い方もload()、dump()と全く同じ感じで使えるので、いったん文字列に起こしてから使いたい場合なんかはこちらを使うのがよいかと思います。

いずれの関数も細かいオプション設定ができるようになっているので、そのあたり詳しくは公式のドキュメントなどをご参照ください。

コマンドラインでの使い方

jsonには、コマンドラインで使うためのツールも用意されています。使用するのは、json.toolというモジュールです。
C:\>echo {"json": "obj", "json2": "obj2" } | python -m json.tool
{
    "json": "obj",
    "json2": "obj2"
}
C:\>echo [1, 2, 3] | python -m json.tool
[
    1,
    2,
    3
]
これはWindows XPで実行した場合です。引数の部分を「"」で囲うか囲わないかといったちがいはあるかと思うのですが、他のOSでもおおむね同じような形で使えるかと思います。

整形されていないjsonファイルを整形したい場合なんかには次のようにすると手軽に整形することができます。
C:\>python -m json.tool < 未整形のjson > 整形後のjson

ちょっとしたときに便利ですね。


・・・余談ですが、このBloggerでは、フィードURLにalt=jsonというパラメータをつけるとjson形式で返してくれます。たとえばこのブログならこんな感じです。練習台として便利なのでよろしければどうぞ。


参考
json - Python公式ドキュメント
JSON - python入門から応用までの学習サイト

2013/06/13

ライブラリ:BeautifulSoup

Pythonの「BeautifulSoup」というライブラリについてご紹介します。

import BeautifulSoup

BeautifulSoupは、バージョン3までと現在最新のバージョン4とでパッケージ名が異なります。バージョン4ではBeautifulSoup4もしくはbs4という名前になっています。
  • バージョン3: BeautifulSoup
  • バージョン4: bs4

今回はバージョン3を対象に述べていきます。ちなみに、バージョン3はPyton 3には対応していないため、Python 3で使うならバージョン4の方を使うことになります。

BeautifulSoup(バージョン3まで)には大きく分けて2つのクラスが入っています。BeautifulSoupとBeautifulStoneSoupです。

ちがいは次の点です。
  • BeautifulSoup: HTML用
  • BeautifulStoneSoup: XML用
(ちなみに、BeautifulSoupのバージョン4では、BeautifulStoneSoupはBeautifulSoupに吸収され存在しません)。

基本的な考え方はHTMLでもXMLでも同じなので、今回はElementTreeと対比させる意味も含めて、後者のBeautifulStoneSoupの方を見ていきます。

XMLファイルの読み込み

from BeautifulSoup import BeautifulStoneSoup

XMLFILE = 'sample.xml'

f = open(XMLFILE, 'r')
soup = BeautifulStoneSoup(f.read())
f.close()
XMLファイルを読み込むには、通常のファイルオープンをしてテキストを抽出し、そこからBeautifulStoneSoupインスタンスを生成します。

以下、samle.xmlには以下の内容が入っていると想定してみていきます。
<post attrA="value A" attrB="value B">
    <title>This is a title.</title>
    <categories>
        <!-- This is a comment. -->
        <category term="Asia"/>
        <category term="South America"/>
        <category term="Europe"/>
    </categories>
</post>

データの読み方

上のコードのとおりXMLのおおもととなるインスタンスsoupを生成したら、あとは木を辿ってデータを見ていきます。木を辿るのに使うのは、主に次のふたつのメソッドです。
  • soup.find()
  • soup.findall()

BeutifulStoneSoupでは、各ノードを「Tag」インスタンスとして保持します。各ノードの情報にアクセスするには、主に次のアトリビュート・メソッドを用います。
  • tag.name
  • tag.string
  • tag.attrs
  • tag.get()

以下、いろいろ見ていきます。

print soup.__class__.__name__
# BeautifulStoneSoupと出力
上のコードで生成したsoupはBeautifulStoneSoupのインスタンスです。

print soup.find('category').__class__.__name__
print soup.find('category').name
print soup.find('category').get('term')
print soup.find('category').attrs
# 以下のとおり出力
# Tag
# category
# Asia
# [(u'term', u'Asia')]
tag.find(タグ名)で子孫のノードにアクセスすることができます。各タグはTagのインスタンスです。nameにはそのタグ名が入っています。get()あるいはattrsで、タグのアトリビュート情報にアクセスできます。BeautifulStoneSoupでは、parse読み出した文字列をすべてユニコードに変換して扱います。

print soup.find('title').string
# 以下のとおり出力
# This is a title.
tag.stringにはそのタグ内の文字列が入っています。

es = soup.findAll('category')
for e in es:
    print e.name, e.get('term')
# 以下のとおり出力
# category Asia
# category South America
# category Europe
tag.find(タグ名)が最初に引っかかった要素を1つだけ返すのに対し、tag.findAll(タグ名)は引っかかった要素をすべてリストにして返してくれます。

es = soup.findAll('category', term='Europe')
for e in es:
    print e.name, e.get('term')
# 以下のとおり出力
# category Europe
find()、findAll()を使うときは、タグ名だけでなくアトリビュートも手がかりに検索することができます。ここでは、termの値が「Europe」となる要素を検索しています。

print soup.post.title.string
# 以下のとおり出力
# This is a title.
タグの親子関係をもとにデータを取得することも可能です。この場合は、soup以下にある「post」タグの下にある一番最初の「title」タグを取得しています。

その他の機能

# 整形表示
print soup.prettify()
取得したXMLを整形して表示するために、prettify()というメソッドが用意されています。

# 元データのエンコード
print soup.originalEncoding
元データの文字コードは、originalEncodingで確認することができます。

# 子要素を取得
print soup.post.categories.contents
# 以下のとおり出力
# [u'\n', u' This is a comment. ', u'\n', <category term="Asia"></category>, <category term="South America"></category>, <category term="Europe"></category>]
contentsを使えば、タグだけでなく、コメントなどの文字列も含めて子要素を取得することができます。ただ、元のXMLデータに空白や改行が入っていると、思わぬところでインデックスが変わってしまったりしてハマりがちですので、タグ要素だけに着目するのであれば、find()、findAll()などを使うのがよいかと思います。


以上です。

今回は取り上げませんでしたが、このほかにもBeautifulSoupには
  • あるノードの隣のノードや親ノードを取得する機能
  • XMLを編集する機能
なんかも備わっています。さらに詳しくは参考ページなどをご参照いただければと思います。

また、BeautifulSoupのバージョン3までとバージョン4とでは互換性の無い部分がところどころあるので、その点にも注意が必要かと思います。今回のBeautifulStoneSoupは、バージョン3までの機能です。


インストール
「pip」が入っていれば、コマンドラインから「pip install beautifulsoup」でインストールできます(BeautifulSoup4は「pip install beautifulsoup4」)。


参考
BeautifulSoup - PyPI
Beautiful Soup: We called him Tortoise because he taught us.
Beautiful Soupドキュメント — BeautifulSoup Document 0.1 documentation
BeautifulSoupでスクレイピングのまとめ « taichino.com
BeautifulSoupでHTML解析 - Perl使いのPythonちゃん

Beautifulsoup4 - PyPI
Beautiful Soup 4 Documentation
※最後の2つは BeautifulSoup4 関連です

2013/06/05

ライブラリ:ElementTree

Pythonの「ElementTree」というライブラリについてご紹介します。

from xml.etree.ElementTree import *

PythonにはXMLを扱うためのメジャーなライブラリがいくつか存在します。シェアがどのようになっているかはよくわからないのですが、個人的によく見かけるのは、ElementTree、BeautifulSoup、lxmlあたりでしょうか。minidomもときどき目にします。

今回はそのうちの「ElementTree」について見てみたいと思います。

「ElementTree」は、XMLをファイルやテキストから読み込んだり、加工したり、保存したりするためのライブラリです。Python2.5から標準ライブラリとなり、別途インストールをすることなく最初から使うことができます。

ファイルからの読み込み

from xml.etree import ElementTree

XMLFILE = "sample.xml"

tree = ElementTree.parse(XMLFILE)  # ファイルから読み込み
root = tree.getroot()
print root.tag  # feedと出力
ファイルからの読み込みにはparse()を使います。続いてgetroot()でルートとなるノードを取得しから処理を進める、というのが定番の流れとなっています。

以下、sample.xmlの中身が次のようなものだと仮定して見ていきます。
<feed attrA="value A" attrB="value B">
    <title>title C</title>
    <categories>
        <category term="Asia" />
        <category term="South America" />
        <category term="Europe" />
    </categories>
</feed>

要素情報の検索と取得
XML要素のタグ、属性はtag、attribアトリビュートに格納されています。
print root.tag  # feed
print root.attrib  # {'attrB': 'value B', 'attrA': 'value A'}
attribは、属性と値のセットを辞書として格納しています。

要素の子要素を見るには、次のようにします。
for e in root:
    print e.tag  # title, categoriesと出力

子要素の中から特定の子だけを取り出すには、find()を使います。
e = root.find('title')
print e.tag  # titleと出力
print e.text  # title Cと出力
textアトリビュートには、その要素の中にあるテキストが格納されています。

find()は上から走査して、最初に見つかった要素1つだけを返します。すべての要素を取得する場合はfindall()を使います。
es = root.findall('category')
for e in es:
    print e.tag, e.attrib  # 出力なし

ただこの場合は、categoryはfeedの直接の子ではなく孫要素にあたるため、findall('category')では取得することができません。直接の子要素だけでなく、すべての子孫要素の中からすべて取得するにはfindall()の引数の頭に「.//」を追加します。
es = root.findall('.//category')
for e in es:
    print e.tag, e.attrib
# 以下のように出力
# category {'term': 'Asia'}
# category {'term': 'South America'}
# category {'term': 'Europe'}

さらに、属性値も手がかりにして要素を検索するには次のようにします。
es = root.findall(".//category[@term='Asia']")
for e in es:
    print e.tag, e.attrib
# category {'term': 'Asia'}と出力
属性名の前に@をつけ、属性値と=でつなげて使います。クオートは必ず「'」(シングルクオート)を使います。「'」が「"」になっていたり、間に空白が挟まっていたりするとうまく検索できないので注意が必要です。

この他にも、find()・findall()には「指定した要素の子要素だけ」、「指定した要素を子に持った親要素だけ」を抽出するような機能なんかも備わっています。find()・findall()の文法については、公式サイトのXPathシンタックスに関するパートにまとめられていますので詳しくはそちらをご参照ください。

次に、文字列から起こすやり方を見てみます。

文字列からの読み込み

xml = """

    text B
    
    
    

"""

e = ElementTree.fromstring(xml)  # 文字列からの読み込み
文字列からElementを生成するには、fromstring()を使います。fromstring()で作った変数は、ファイルから読み込んだときのrootと同じように使うことができます。

最後に、ファイルに保存するやり方を。

ファイルへの書き込み

XMLFILEOUT = 'sampleout.xml'

tree = ElementTree.ElementTree(e)
tree.write(XMLFILEOUT)  # ファイルへの書き込み
上で文字列から読み込んだeをファイルに保存するには、それを内包するElementTreeというものを生成した上で、write()メソッドで行います。

ファイルから開いたtreeの場合は直接write()で保存できます。

ちなみに、この「ファイルから読み込んだ場合と文字列から読み込んだ場合のちがい」は、ファイルからparse()で開いた場合はElementTreeオブジェクトのインスタンスが生成されるのに対し、文字列からfromstring()で開いた場合はElementオブジェクトのインスタンスが生成される、というちがいに起因しています。詳しくは公式ドキュメントをあたっていただくのがよいかと思います。

以上です。


ElementTreeにはこれらの他にも、文字列を検索するfindtext()、属性を追加するset()、子要素を追加するinsert()など、XMLを手軽に扱える便利な機能が数多く用意されています。

もっと詳しい部分については公式のドキュメントや、以下参考リンクをご参照ください。


インストール
「ElementTree」はPython 2.5から標準ライブラリに含まれています。Pythonと別途インストールする必要はありません。


参考
ElementTree - Python公式ドキュメント
PythonでElementTreeを使ってXMLを処理する方法 - Sticker@Something
easiest way to parse xml in python - Stack Overflow

2013/05/31

ライブラリ:xlwt

Pythonの「xlwt」というライブラリについてご紹介します。

import xlwt

「xlwt」は、PythonからExcelファイル(xls)に書き込むためのライブラリです。読み込む方の「xlrd」と対になっています。

機能はシンプルで、1)ブックとシートを作成して、2)シートに書き込む、という流れで使います。xlrdと同じく、「ブック→シート→セル」という構成を頭に置いておくと理解しやすいかと思います。

以下、使い方を見ていきます。

データの保存

import xlwt

# データを保存するファイルとシートの名前
FILE = 'test.xls'
SHEET = 'testSheet01'

# WorkbookとWorksheetを作成
book = xlwt.Workbook()
s = book.add_sheet(SHEET)

# データをシートに書き込み
mydata = [1, 2, 3, 4, 5]
for i, ele in enumerate(mydata):
    # 0行、i列目にデータeleを書き込み
    s.write(0, i, ele)

# ファイルに保存
book.save(FILE)
データを保存するために最小限必要なのは
  • Workbook()
  • add_sheet()
  • write()
  • save()
の4つです。流れとしては、ブックを開いて、シートを追加して、シートに書き込んで、ブック全体をファイルに保存、という形になります。

現状、既存のファイルに追加書き込みをすることはできないため、原則新規作成です。

関数の使用

s.write(1, 0, xlwt.Formula('SIN(A1) * 2'))
セルに値ではなくExcelの関数を挿入したい場合は、Formulaオブジェクトを使います。上記のようにすると、上から2行目、左から1つめのセル(A2セル)に数式「SIN(A1) * 2」が書き込まれます。Excel上で数式を書くときの=(イコール)は必要ありません。

余談ですが、数式の中で他のセルを指定する場合、「A1」「B4」といった形での指定になります。行番号の部分は整数でシンプルでいいのですが、列番号の部分は「A, B, C, ..., Z, AA, AB, AC, ...」といった形でアルファベットによる26進法になるので、少し工夫が必要です。26列目よりも右側(AA以降)を使う場合には、たとえば、次のように、列指定のためのCOLというリストをひとつ作っておくと便利です。
COL = []
ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
ALPHAS = ' ' + ALPHA
for d1 in ALPHAS:
    for d2 in ALPHA:
        COL.append((d1 + d2).strip())
print COL
# COL = ['A', 'B', ...'Z', 'AA', 'AB', ...]

書式の設定

style0 = xlwt.easyxf(strg_to_parse='font: name Meiryo, color-index red, bold on',
                     num_format_str='#,##0.00')
s.write(2, 0, 12.3, style0)
セルの書式を設定するには、easyxf()という関数を使います。ふたつの引数strg_to_parse、nu_format_strのうち、前者はフォントやアラインメント(セル内での表示位置)などを指定します。後者は、数値や日付のフォーマットを指定するのに使います。

以上です。

xlwtは、OSがWindowsでなくても動作するということでその点は便利なのですが、名前付きセル、フィルタ、ピボットテーブルといった機能は現状備えていないようです。ですので、何か凝ったことをしようとするのではなく、あくまでも、データをエクセルに保存する、というシンプルな使い方に留めておいた方が良さそうです。


インストール
pip」が入っていれば、コマンドから「pip xlwt」と打つとインストールすることができます。


参考
xlwt - pypi
Examples Generating Excel Documents Using Python’s xlwt - if(you.like('programming'))
Excel書き込み (xlwt) - python入門から応用までの学習サイト

2013/05/24

ライブラリ:xlrd

Pythonの「xlrd」というライブラリについてご紹介します。
import xlrd

「xlrd」は、Excel(xls)のデータをPythonで読むためのライブラリです。「xlrd」というのはおそらく「excel read」の省略形で、対となる「xlwt」というものも存在します。

xlrdでは、「Book→Sheet→Cell」という構造でエクセルデータを抽出します。

まずはBookから。

Excelファイルを開くには、関数open_workbook()を用います。CSVファイルを開く関数csv.reader()の場合は、ファイルオブジェクトを引数に取りましたが、xrdの場合はファイル名を直接受け取ります。
FILE = 'excelbook.xls'
book = xlrd.open_workbook(FILE)

open_workbook()でExcelファイルを開いたら(Bookオブジェクトを作成したら)、アトリビュートやメソッドを使ってその中身の情報にアクセスすることができます。
# 文字コード
print 'encoding:', book.encoding

# シートの枚数
print 'number of sheets:', book.nsheets

# シートの一覧(名前、データの入った行と列の数)
print 'sheets:'
for s in book.sheets():
    print '%s %sx%s' % (s.name, s.nrows, s.ncols)
シートの中身を取得するには、BookからSheetオブジェクトを取得した後、cell()メソッドを使います。
# Sheet1という名前のシートを取得
s = book.sheet_by_name('Sheet1')

print s.cell(1, 3)  # 指定した行・列のCellオブジェクトを取得
print s.cell_type(1, 3)  # セルのtypeを取得
print s.cell_value(1, 3)  # セルのvalueを取得
Sheetを取得するには、シートの名前で取得する方法sheet_by_name()とシートのインデックスで取得する方法sheet_by_index()とがあります。

各セルには「type」と「value」という情報が入っています。typeには文字列、数値といったセルのフォーマット情報が、valueにはデータの値が入っています。typeは
  • 1: 文字列
  • 2: 数値
  • 3: 日付
といった形であらかじめ番号が割り当てられているので、詳細は公式のドキュメントのセルについての部分でご確認いただくとよいかと思います。

行番号、列番号が0始まりの数字であることに注意が必要です。0始まりなので、たとえば、cell(1, 3)とした場合は、エクセル上で見ると、上から2行目、左から4列目のセルにアクセスしていることになります。

セル単位ではなく、行単位、列単位でデータを取得したい場合のために、row()、col()といった関数も用意されています。
s.row(0)  # 最初の行のセルをリストで取得
s.col(0)  # 最初の列のセルをリストで取得
s.col_values(0)  # 最初の行の値をリストで取得

以上です。


インストール
「setuptools」と「pip」が入っていれば、コマンドから「pip install xlrd」と打つとインストールできます。


参考
xlrd - pypi
Python Excel
xlrd extension - Lingfo

2013/05/14

ライブラリ:csv

Pythonの「csv」というライブラリについてご紹介します。

import csv

「csv」は、CSVファイルの取り扱いをカンタンにしてくれるライブラリです。おもな機能はCSVの「書き込み」と「読み込み」です。以下、順に見ていきます。

CSVファイルへの書き込み

import csv

FILE = 'sample.csv'

title = ['a', 'b', 'c', 'd', 'e']
mylist = [[10, 68, 43, 25, 64],
          [42, 62, 34, 67, 36],
          [44, 41, 59, 77, 68],
          [90,  7, 24, 91, 82],
          [42, 64, 43,  6, 96],
          [76, 74, 62, 64, 66],
          [ 1, 96, 91,  0, 79]]

f = open(FILE, 'wb')

c = csv.writer(f)  # CSV書き込み用オブジェクトの生成
c.writerow(title)  # 1行書き込み
c.writerows(mylist)  # 複数行書き込み

f.close()
CSVファイルへの書き込みはまず、ファイルを開いた後、writer()関数でcsv writerオブジェクトを生成します。その後そのwriterオブジェクトを使って、1行ずつ、あるいは複数行まとめて書き込んでいきます。1行の場合はwriterow()、複数行の場合はwriterows()が使えます。

この例では次のような内容のcsvファイルが作られます。
a,b,c,d,e
10,68,43,25,64
42,62,34,67,36
44,41,59,77,68
90,7,24,91,82
42,64,43,6,96
76,74,62,64,66
1,96,91,0,79

CSVファイルの読み込み

f = open(FILE, 'rb')

mylist2 = []
c = csv.reader(f)  # CSV読み込み用オブジェクトの生成
for row in c:
    mylist2.append(row)
print mylist2

f.close()
CSVファイルの読み込みも、保存とほぼ同じ形で行います。保存がwriter()を使ったのに対し、読み込みではreader()を使います。reader()オブジェクトはイテレータとして扱うことができます。

また、区切り文字やデータを囲うための文字についてはオプションによって指定することが可能です。たとえば、区切り文字が空白で、コンマを含むデータを囲う文字が「|」の場合は
c = csv.reader(f, delimiter=' ', quotechar='|')
と書くことができます。

さらに、ファイルへの書き込みについては、「データを囲うための文字をどのぐらい使うのか」という部分も指定することが可能です。quotingオプションを使います。たとえば、コンマを含むような必要最小限のデータのみを囲いたいときは
c = csv.writer(f, delimiter=' ',
    quotechar='|', quoting=csv.QUOTE_MINIMAL)
とします。その他のスタイルとしては
csv.QUOTE_ALL すべてのデータを囲う
csv.QUOTE_NONNUMERIC 非数値データをすべて囲う
csv.QUOTE_NONE 囲いは使わない
などを選択することが可能です。

・・・以上です。


インストール
「csv」は標準ライブラリに含まれているので、Pythonと別途インストールする必要はありません。


参考
csv - Python公式ドキュメント
csv - Python-izm
csv - Doug Hellmann

2013/05/06

ライブラリ:pickle

Pythonの「pickle」というライブラリについてご紹介します。

import pickle

「pickle」は、Pythonオブジェクトをファイルに保存するためのライブラリです。保存したものをまた読み出してくるための関数もあわせて用意されています。

私の認識だと、ただ「ファイルに保存するためのもの」という感じなのですが、OOPではこの処理を「シリアライズ(serialize)」「デシリアライズ(deserialize)」と呼ぶそうです(Wikipedia)。

ちなみに、pickleは「ピクルス」のピクルでいわゆる「漬物」のこと。オブジェクトを漬けるというたとえでしょうか。

pickleの使い方はとてもシンプルです。以下、pickleの使い方について述べてみます。

オブジェクトをファイルに保存する

pickleでファイルに保存するには、pickle.dump()を使います。
mydict = {1: 'Pochi',
          2: 'Taro',
          3: 'Jiro'}
with open('xxx.dump', 'w') as f:
    pickle.dump(f, mydict)

2つの引数のうち、最初のもの(f)は「書き込む可能なファイルオブジェクト」、ふたつめ(mydict)には「保存したいオブジェクト」を指定します。

追記: 上のコードおよび説明が間違っておりました。正しくは、 pickle.dump() に渡す 2 つの引数は、最初の引数が「保存したいオブジェクト」で 2 つめが「書き込み可能なファイルオブジェクト」です。ですので該当行も次のとおりにするのが正解です。

with open('xxx.dump', 'w') as f:
    pickle.dump(mydict, f)

こうすると、「xxx.dump」というファイルが作られ、この中にmydictがシリアライズされて保存されます。

オブジェクトをファイルから読み出す

いったんpickleしたオブジェクトをファイルから再び取り出すには、pickle.load()を使います。
with open('xxx.dump', 'r') as f:
    mydict_load = pickle.load(f)
    print mydict_load  # {1: 'Pochi', 2: 'Taro', 3: 'Jiro'}

引数には、読み込む可能なファイルオブジェクトを渡します。

メインはこのdump()とload()の2つで、あとは、これをファイルではなく文字列にしたい場合のためのdumps()、loads()などが用意されている形です。


今回は辞書型のオブジェクトを使いましたが、pickleではほかにもさまざまなオブジェクトを扱うことができます。公式ドキュメントによるとpickle可能なものとして次のものが挙げられています。
  • None True False
  • 整数型 浮動小数点型 複素数型
  • 文字列
  • タプル リスト セット 辞書
  • モジュールのトップレベルで定義された関数
  • モジュールのトップレベルで定義されたビルトイン関数
  • モジュールのトップレベルで定義されたクラス
  • __dict__がpickle可能なインスタンス

・・・以上です。


インストール
「pickle」は標準ライブラリに含まれているので、Pythonと別途インストールする必要はありません。


参考
pickle - Python公式ドキュメント
Pythonオブジェクトをシリアライズする - Dive Into Python 3 日本語版

2013/04/29

ライブラリ:shelve

Pythonの「shelve」というライブラリについてご紹介します。

import shelve

「shelve」は、Pythonオブジェクトをファイルに保存し永続化するためのライブラリです。簡易的なデータベースとして使うことができます。インタフェースが辞書型データと非常によく似ているため、シンプルに使うことができます。

ただ、個人的にはほとんど使ったことがないため細かいところがまだよくわかっていません。以下、今回調べた基本的な使い方だけ見てみます。

オブジェクトデータの保存

FILENAME = 'my.shelve'

d = shelve.open(FILENAME)
d['dogs'] = ['Taro']
d.close()
オブジェクトの保存は通常のファイルへの保存と同じように、open()とclose()の間に処理を書く形で行います。

openして得たshelveオブジェクトに、「キー&バリュー」の形でデータを与えます。ファイルが存在しない場合は新規に作成してくれます。

オブジェクトデータの読み込み

d = shelve.open(FILENAME)
print d  # {'dogs': ['Taro']}
print d['dogs']  # ['Taro']
print 'dogs' in d  # True
d.close()
shelveで保存したデータはopen()で読むことができます。shelveオブジェクトは辞書型のデータと同じように扱うことができます。

オブジェクトデータの追加

d = shelve.open(FILENAME)
dogs = d['dogs']
dogs.append('Pochi')
dogs.append('Jiro')
d['dogs'] = dogs
d.close()

d = shelve.open(FILENAME)
print d  # {'dogs': ['Taro', 'Pochi', 'Jiro']}
d.close()
バリューの部分をリストにした場合などにそのリストに要素を追加する場合には、いったんそのリストを取り出し、値を追加した後に元に戻します。

・・・以上です。


インストール
「shelve」は標準ライブラリに含まれているので、Pythonと別途インストールする必要はありません。


参考
shelve Python Module of the Week
shelve - Python公式ドキュメント