2014/05/26

Python Tips:標準入力から文字列を取得したい

Pythonで入力を取得する方法をご紹介します。

Pythonでは、入力を取得する方法が大きく分けて2種類あります。

  • raw_input
  • sys.stdin.readline readlines read


以下、それぞれについて順に見ていきます。


raw_input

raw_input はコマンドラインからの入力を取得するための関数です。特にライブラリを import しなくても使える組み込みの関数となっています。

input_line1 = raw_input()
print input_line1 + " is written"
# => 入力された文字列 is written

raw_input で得られる文字列は、入力された文字列から自動的に改行文字を取り除いてくれます。

ちなみに Python3 ではこの raw_input は廃止されており、 input という別の名前の組み込み関数が用意されています。

sys.stdin.readline readlines read

sys.stdin.readline のシリーズは、raw_input よりも広い用途で標準入力を取得するための関数群です。

sys ライブラリを import することで使えるようになります。

readline readlines read のちがいを以下順に見ていきます。

import sys
input_line2 = sys.stdin.readline()
print input_line2 + " is writen"
# => 入力された文字列
#  is written

readline は標準入力から1行取得するための関数です。 raw_input とのちがいは、 raw_input が改行文字を自動的に削除するのに対し、 readline は標準入力に与えられた内容をそのまま取得してくる点です。

input_lines1 = sys.stdin.readlines()
print input_lines1
# => 入力された文字列を1行ずつ格納したリスト

readlines は標準入力から複数行取得するための関数です。戻り値はリストで、入力された文字列が1行ずつ要素として格納されています。こちらも改行文字の自動削除はありません。

input_lines2 = sys.stdin.read()
print input_lines2
# => 入力された文字列

read は標準入力から複数行取得するための関数です。 readlines が結果をリストに格納するのに対して、 read は結果をそのまま1つの文字列として取得します。

readline readlines read とそれぞれ少しずつちがうので、用途にあわせて使い分けるとよいかと思います。

以上です。

余談ですが、指定した回数だけ入力を受け付けたいときなんかは
[raw_input() for _ in range(3)]
などと書くと、Pythonらしく(?)書くことができたりします。


参考
27.1. sys — System-specific parameters and functions — Python公式ドキュメント

2014/05/20

Python Tips:リストの中の要素を要素別にカウントしたい

Pythonで、リスト中の要素の数を数える方法をご紹介します。

いちばんかんたんなのは collections ライブラリの Counter クラスを使う方法です。
import collections

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

s1 = 'すもももももももものうち'

count_dict = collections.Counter(s1)
# => Counter({'も': 8, 'ち': 1, 'す': 1, 'の': 1, 'う': 1})

Counter クラスのインスタンスは、辞書のような形で要素とその個数を格納したオブジェクトとなります。

上の例では文字列 s1 を渡していますが、リストを渡した場合でも同様に動作してくれます。

この Counter インスタンスから各要素を取り出すには items() keys() values() など辞書型と同名のメソッドを使います。
for k, v in count_dict.items():
    print k, v,
# => ち 1 も 8 す 1 の 1 う 1

順番に取り出すだけでなく、「多い方から◯個」といった取り出し方も可能です。多い方から指定した数だけ取り出すには most_common メソッドを使います。
print count_dict.most_common(2)
# => [('も', 8), ('ち', 1)]

順序は保存されていませんが、元の要素を分解して取り出すことなんかも可能です。
[x for x in count_dict.elements()]
# => ['す', 'も', 'も', 'も', 'も', 'も', 'も', 'も', 'も', 'う', 'の', 'ち']


以上です。


参考
python - How to count the frequency of the elements in a list? - Stack Overflow
8.3. collections — High-performance container datatypes — Python v2.7.6 documentation

2014/05/06

ライブラリ:bisect

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

import bisect

この bisect ライブラリは、名前のとおり bisection search ーーいわゆる二分探索法の関数を提供するライブラリです。

すでにソートされた配列に対して、関数ひとつで二分探索法を行ってくれます。

具体的には、大きく分けて2種類の関数が用意されているので、それらを順番に見ていきます。
bisect_***
insort_***


bisect_***

bisect から始まるメソッドは、二分探索法により指定した値が入るべき箇所の「探索」を行います。探索のみを行い、実際の挿入は行いません。
import bisect

li = [1, 9, 15, 32]
x = 15

print bisect.bisect_left(li, x)
# => 2

print bisect.bisect_right(li, x)
# => 3
bisect_left bisect_right はいずれもふたつの引数を受け取り、ひとつめはソート済みのリスト、ふたつめは単一の値を受け取ります。

いずれも、「ソート済みリストの適切な位置にある値を挿入するとしたら、何番目に挿入することになるか?」というのを調べて返してくれます。元のリストは変更しません。

bisect_left は、同じ値がすでに入っていた場合に、いちばん左に新しい値を挿入すると考えて、その位置を返します。

一方、 bisect_right は、同じ値がすでに入っていた場合に、いちばん右側に挿入するものとして、その位置を返します。

いずれもオプション引数 lo hi を受け取ることができます。 lo はリストの挿入すべき位置の下限を、hiは上限を指定するために使えます。
print bisect.bisect_left(li, x, lo=0, hi=1)
# => 1

left や right のついていない bisect という関数もあり、これは bisect_right と同じ挙動をします。


insort_***

insort から始まるメソッドは、二分探索法により指定した値を適切な位置に「挿入」します。 bisect が探索のみを行うのに対し、こちらの insort は実際の挿入を行います。
bisect.insort_left(li, x)
bisect.insort_right(li, x)

print li  # => [1, 9, 15, 15, 15, 32]
bisect と同様に、 insort_left insort_right もふたつの引数を受け取り、ひとつめにソート済みリストを、ふたつめに挿入したい要素を受け取ります。

いずれも渡されたリストそのものを変更します。

bisect の場合と同様、末尾に left とついている insort_left は挿入できる箇所が複数あったときにいちばん左側に、 insort_right はいちばん右側に挿入します。

left や right のついていない insort というメソッドもあり、こちらは insort_right と同じ挙動をします。
print bisect.insort(li, x)

bisect の場合と同じく insort の場合も挿入する範囲を制限するために lo hi という引数をオプションで与えることができます。

以上です。


参考
8.5. bisect — 配列二分法アルゴリズム — Python 2.7ja1 documentation
The bisect module - (the eff-bot guide to) The Standard Python Library

2014/05/01

ライブラリ:peewee

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

from peewee import *

peewee はPythonでデータベースを扱いやすくするためのライブラリーーいわゆる「ORマッパ」ライブラリです。デフォルトではPosgreSQL、MySQL、SQLiteの3つに対応しており、Ruby on RailsのActiveRecordに似たインタフェースを提供しています。

以下、peeweeの基本的な使い方をひととおり見ていきます。


データベースへの接続

データベースへの接続は、***Databaseというクラスを使って行います。
# データベースを指定して接続
db = SqliteDatabase('db.sqlite')
db.connect()

# さまざまな処理...

# データベース接続を閉じる
db.close()

これはSqliteの場合です。ほかのDBMSの場合はそれに対応したクラスを使います。


モデルの定義

# データベース指定のための設定を格納したベースモデル
class BaseModel(Model):
    class Meta:
        database = db

# モデル Person
# person テーブルに対応する
# カラムとして name birthday を持つ
# データベースの指定は BaseModel を継承する形で行う
class Person(BaseModel):
    name = CharField()
    birthday = DateField()

    def __unicode__(self):
        return self.name


テーブルの作成

# Person クラスに対応した person テーブルを作成する
def create_tables():
    Person.create_table()

create_tables()

この create_table とは逆に、存在するテーブルを削除するメソッドは drop_table です。


レコードの追加 (C in CRUD)

# Person クラスのインスタンスを生成し
# save メソッドでデータベースへ登録する
from datetime import date

def create_person(name, birthday):
    new_person = Person(name=name,
                        birthday=date(*birthday))
    return new_person.save()

create_person(name="name", birthday=(2014, 5, 5))


レコードの取得 (R in CRUD)

# 条件にマッチしたものを1件だけ取り出す
saigo = Person.get(Person.name == 'Saigo')
print saigo.name  # => Saigo

# 条件にマッチしたものを複数件取り出す
saigo_family = Person.filter(Person.name == 'Saigo').execute()
for s in saigo_family:
    print s.name,
# => Saigo Saigo Saigo...

get メソッドは条件にマッチしたものを1件だけ抽出します。後者の filter メソッドと execute メソッドの組み合わせでは、条件にマッチしたものを複数件抽出してきます。 filter で条件を決めてクエリ文を生成し、 execute で実際にデータベースに接続する、といった形です。

ちなみに、 filter で条件を決めたあとに直接 execute でデータベースにアクセスする前に order_by join limit などのメソッドでクエリ文をさらに細かく設定することももちろん可能です。


レコードの削除 (D in CRUD)

# すでにインスタンス化されたレコードを削除する
a_record.delete_instance()

# 条件にマッチしたものをすべて削除する
Person.delete().filter(Person.name == 'Saigo').execute()

delete_instance はすでにインスタンス化されたレコードを削除します。一方で、 delete のあとに filter などで条件を設定し execute とすると、条件にマッチしたものがすべて削除されます。


レコードの更新 (U in CRUD)

# すでにインスタンス化されたレコードを更新する
a_record.name = "new name"
a_record.save()

# 条件にマッチしたものをすべて更新する
Person.update(name = "Saigoh").filter(Person.name == 'Saigo').execute()

save は インスタンス化されたレコードを更新します。一方で、 update のあとに filter などで条件を設定し execute とすると、条件にマッチしたものをすべて update 内の式のとおりに更新します。

以上です。


この他にも、データベース操作をかんたんにしてくれるさまざまなメソッドが用意されています。

詳しくは公式ドキュメントを参照してみてください。


インストール

pip が入っていればインストールは pip から行えます。
$ pip install peewee


参考
SQLAlchemyとpeeweeの比較 - kk6のメモ帳*
紹介マニアどらふと版: Python の ORM 調査:結論
Welcome to Peewee, a lightweight python ORM - IPython Notebook Viewer
peewee - Python is Simple
coleifer/peewee - GitHub
peewee — peewee公式ドキュメント