Python


構築環境

  • python.example.com  
  • CentOS release 6.7 
  • ja_JP.utf8  
  • Python 2.6.6

サイト -Python 事始め リンク



<基本文法>

データ型

整数型  
浮動小数点型  
文字列型  
リスト型 ・・・配列の様なもの
辞書型 ・・・連想配列の様なもの

関数とメソッド

f = open(sys.argv[1]) ・・・openは関数
x = f.read() ・・・readはメソッド

コメント

# ・・・行コメント
""" ・・・複数行コメント

3連クォート

シングルクォート ・・・3つ並べて'''
ダブルクォート ・・・3つ並べて"""
普通の書き方
str = "select"
str = str + " count(*)"
str = str + "from emp;"
3連クォートを使うと複数行に跨る長い文字列を簡単に書ける str = """
select
count(*)
from emp;
"""

文字列の特定の要素の取り出し

a = 'xyz'    
戻り値 説明
a[0] x 0番目
a[-1] z 末尾の1番目
'xyz'.upper()[1] y 関数やメソッドの戻り値の1番目
a[0:1] x 0番目から1番目の手前
a[:2] xy デフォルト(0番目)から2番目の手前
a[1:] yz 1番目からデフォルト(末尾)まで
a[1:-1] y 1番目から末尾の手前

リスト

a = [1, 2, 3]    
b = ['abc', 'def' ,'ghi']    
戻り値 説明
a[0] 1 0番目の要素
a[-1] 3 末尾の要素
a[-1]=4   末尾の要素を変更
a.append(9)   要素を追加
b[1:2] 'def' 1番目から2番目の手前までの要素
値が辞書型
>>> die = [{"id": 0, "name": "Hero"},{"id": 1, "name": "Dunn"}]
要素の取得
>>> die[0]
{'id': 0, 'name': 'Hero'}
0番目の要素のkey"name"のvalueを取得
>>> die[0]["name"]
'Hero'
全要素のkey"name"のvalueを取得
>>> for var in die:
...     print var["name"]
Hero
Dunn
全要素に新たなkey:valueを追加(valueはリスト型)
>>> for var in die:
...     var["age"] = []
>>> print die
[{'age': [], 'id': 0, 'name': 'Hero'}, {'age': [], 'id': 1, 'name': 'Dunn'}]
新たに追加したkey"age"に値をセット
>>> die[0]["age"].append(20)
>>> print die[0]
{'age': [20], 'id': 0, 'name': 'Hero'}
>>> print die[1]

タプル

リストは変更可能だが、タプルは変更不可
x = (1, 2, 3)    
戻り値 説明
x (1, 2, 3)  
a[0] 1 0番目の要素が表示される
x(0) TypeError: 'tuple' object is not callable 関数やメソッド(引数)と認識されエラーになる
a[0]=4 TypeError: 'tuple' object does not support item assignment タプルは要素を変更出来ない

インポート

import sys ・・・モジュール単位でインポート
from sys import argv ・・・メソッド単位でインポート

文の最後のコロン(:)とインデント

条件式の区切りを意味する
for i in range(len(y)):
    if a == b:
        pass
    else
        print 'a != b'
pythonには構文の終わりを示す記号がない。構文の区切りはインデントに積極的な意味を持たせることで示す

文の最後のカンマ(;)

改行を抑制する。特に指定しないと引数を表示したあと自動的に改行される
print line,

文の最後の円マーク(\)

条件式の継続文字
if (hoge >= '2000/04/01' and hoge <= '2001/'03/31' or \
    hoge >= '2003/04/01' and hoge <= '2004/03/31') :
    print 'bad range'

Perlのchomp

文字列の末尾の改行文字を削除する
if line and line[-1] == '\n':
    line = line[:-1]

例外

全ての例外を一律で記述
try:
    スクリプト内容・・・
    if value != 1:
        raise ValueError    # 例外を発生させる
exception Exception s:
    print s
finally:
    f.close()

辞書型 {キー:値}

初期化 die = {}
値の取得 die[キー] または die.get(キー)
キーの追加 die[キー]=値
キーの削除 del die[キー]
キーの一覧 die.keys()
値の一覧 die.values()
キーと値の一覧 die.items()
浮動小数点はキーに出来る dic[12.5] = 12.5
タプルはキーに出来る

dic[(1,2)] = 3   ※()は省略可 dic[1,2] = 3

                   ※ 後から変更不可のタプルはキーに指定できるが、

                      後から変更可能なリストはキーに指定できない

keyのデータ型は統一する必要はない
>>> die = {1:'apple', 'two':'orange'}
>>> die[1]
'apple'
>>> len(die)    キーと値のペア数
2
>>> for k, v in die.items():    キーと値の一覧を表示
...     print k, v
...
1 apple
two orange
>>> for v in die.values():    値の一覧を表示
...     print v
...
apple
orange

値の部分を辞書型に出来る
>>> die = {'taro':{'age':18, 'high':170}, 
           'jiro':{'age':23, 'high':160}}
>>> die['taro']
{'high': 170, 'age': 18}

<ファイル操作>

テスト用ファイル

$ vim profiles.txt
*太郎
年齢:18
身長:170
性格:おっとり
出身:北海道

*ハリー
年齢:20
出身:アイダホ
性格:神経質
髪型:よこわけ

*ゆかり
性格:女
年齢:15
好物:おにぎり
# coding:utf-8

def prink(e):
    """日本語交じりのデータ内容を表示する。"""
    print eval('"""%s"""' % str(e))

print help(prink)

"""ファイル全体を巨大な文字列の形で一気に読み込んでしまい、その後、
その文字列を操作する。
"""
f = open('profiles.txt')
x = f.read()
f.close()

dic = {}
person  = ''

"""改行文字でファイル全体を分割して、行単位になったリストをlinesに入れる
"""
lines = x.split('\n')

for line in lines:
    if line and line[0] == '*':
        person = line[1:]
    else:

        """splitの第2引数は分割回数。分割結果(リスト)がkvに格納される 例:['年齢', '18']
        """
        kv = line.split(':', 1)
        if len(kv) == 2:
            if (person, kv[0]) not in dic:
                dic[person, kv[0]] = []

            """辞書の中に、キー:person, kv[0]、値:kv[1]で格納される
            """
            dic[person, kv[0]].append(kv[1])

for (p, attr) in sorted(dic.keys()):
    prink('%sさんの%sは:%s' % (p, attr, dic[p, attr]))


"""ファイルにある各行をループによって1行ずつ読んでいきながら処理する
"""
f = open('profiles.txt')
line = f.readline()
while line:
    スクリプト処理・・・
    line = f.readline()
f.close()

実行結果

$ python people-dic.py
ゆかりさんの好物は:['おにぎり']
ゆかりさんの年齢は:['15']
ゆかりさんの性格は:['女']
ハリーさんの出身は:['アイダホ']
ハリーさんの年齢は:['20']
ハリーさんの性格は:['神経質']
ハリーさんの髪型は:['よこわけ']
太郎さんの出身は:['北海道']
太郎さんの年齢は:['18']
太郎さんの性格は:['おっとり']
太郎さんの身長は:['170']

<ファイル操作 その2>

テスト用ファイル

$ vim category.list
aaaa    000
bbbb    000
cccc    000
dddd    000
aaaa    111
cccc    222
bbbb    222
bbbb    333

summarize.py (キー項目でループさせるパターン)

"""
標準入力から1行づつ読み込む(sys.stdin)
1列目(kv[0])が変わるまで2列目(kv[1])をリストに格納(append)
1列目が変わったらリスト内容をカンマで結合(','.join)して出力。リストはクリア
"""
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

keyword = ''
category = []

for line in sys.stdin:

    kv = line[:-1].split('\t', 1)

    if keyword !=  kv[0] and keyword != '':
        print keyword + '\t' + ','.join(category)
        category = []

    keyword = kv[0]
    category.append(kv[1])

print keyword + '\t' + ','.join(category)

summarize2.py  (辞書(key,[ ]) に格納させるパターン)

"""
標準入力から1行づつ読み込む(sys.stdin)
読み込んだ内容は辞書(1つのkeyに1つのリスト(複数value))に格納する ( setdefault(key, []).append(value) )
すべて読み終えたら、辞書を出力
set()の引数にリストを指定すると重複がなくなる ','.join(set(dic[key])) """
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys dic = {} for line in sys.stdin: kv = line[:-1].split('\t', 1) dic.setdefault(kv[0], []).append(kv[1]) for key in dic.keys(): print key + '\t' + ','.join(dic[key])

実行結果

$ cat category.list | sort | python summarize.py > hoge
aaaa    000,111
bbbb    000,222,333
cccc    000,222
dddd    000

<関数・モジュール・クラス>

関数

公式    ※ def文が呼び出されるまで関数名は定義されないので、関数の呼び出しはdef文の後にこなくてはいけない
def  関数名(引数の並び・・・)

ドキュメントが表示される
print help(関数名)

オプション引数    ※ 関数の呼び出し時、第2引数を省略するとデフォルト':'がセットされる
def 関数名(引数1, 引数2=':'):

可変個の引数    ※ 引数はタプルとして扱われる。関数名(a, b, c)で呼び出された場合、len(引数1)は 3 になる
def 関数名(*引数1)
$ vim test.py def testdef(*par): print len(par), par testdef('a', 'b', 'c') testdef('a', 'b', 'c', 'd') $ python test.py 3 ('a', 'b', 'c') 4 ('a', 'b', 'c', 'd') 辞書を使った呼び出し ※ 引数に**を付けると、関数側で引数を辞書として受け取ってくれる def f(**dic): print dic f(x=20, y='z', f=20.5) 結果 {'y': 'z', 'x': 20, 'f': 20.5}

モジュール

・ある機能を分離して別のファイルに整理したもの
・ファイル名が自動的にモジュール名になる
・他ファイルからのモジュールの呼び出し import モジュール名() モジュール名.関数名(引数・・・)
・特殊モジュール変数:__name__ 呼び出されたモジュールの__name__にモジュール名が自動設定される
・モジュールの最後に__main()関数を定義して、関数の呼び出し部分をその中に記載する
モジュールを直接実行すると、そのモジュールには'__main__'という名前が割り当てられる def __main(): dic = read_file('profiles.txt') disp_dic(dic) if __name__ == '__main__': __main() モジュールを直接実行するとTrue判定され__main関数が呼び出される
・モジュール変数 モジュールファイルのdef文やクラス文の外側に記載した変数。モジュール変数は外からもアクセスできる モジュール名.モジュール変数

クラスの要点

(1) class クラス名
(2) モジュール名はファイル名と同じになる
(3) モジュール名とクラス名は別々に出来る
(4) 1つのモジュール内に複数のクラスを定義出来る
(5) クラスの中に書いた関数をメソッドと呼ぶ
(6) メソッドが呼び出される際の第1引数にはインスタンスが渡される。慣習的に self が付けられる
(7) インスタンス変数は、この self の属性として設定する。 self.dic
(8) 特殊メソッド __init__() はインスタンスが生成された直後に呼び出され、インスタンス変数の初期化を行う
(9) __init__() の定義はオプションなので、定義しなくても問題ない
(10) インスタンス変数はメソッドに対して外から与える情報、かつ外へ伝える情報

テスト用ファイル

$ cat profiles.txt
前述と同様
$ cat profiles5.txt
*太郎
年齢:20
身長:170
好物:パイン

*次郎
年齢:10
出身:鳥取
性格:神経質
$ cat profiles6.txt
*太郎
年齢:20
身長:170
性格:おっとり
出身:硫黄島

*次郎
年齢:10
性格:やさしい
# coding:utf-8

version = '0.1'    # モジュール変数

def prink(e):
    """日本語交じりのデータ内容を表示する。"""
    print eval('"""%s"""' % str(e))

"""モジュールにクラスが1つの場合はモジュール名とクラス名を同じにするのが慣習
1モジュールに複数クラスを記述する場合はモジュール名とは違う名前をクラスに付ける"""
class people:

    def __init__(self):
        self.dic = {}    # インスタンス変数の初期化

    def add_item(self, person, key, value):
        """このメソッドは、辞書dic の(person, key) で示されるキー値に
        valueを追加する。まだ1つも値がない場合には、空のリストを追加
        してvalueが追加できることを保障する"""

        """ dic = self.dic によりローカル変数 dic は インスタンス変数 self.dic を
        指しているので、dic に更新した内容は self.dic にも反映される"""
        dic = self.dic

        if (person, key) not in dic:
            dic[person, key] = []
        dic[person, key].append(value)

    def read(self, filename):
        f = open(filename)
        x = f.read()
        f.close()

        dic = self.dic
        person  = ''

        lines = x.split('\n')

        for line in lines:
            if line and line[0] == '*':
                person = line[1:]
            else:
                kv = line.split(':', 1)
                if len(kv) == 2:

                    """あるメソッドから同じクラスの別のメソッドを呼び出す。
                    引数の * について
                    ・引数に * を付けるとメソッド内では引数をタプルとして受け取る
                    ・可変個の引数をもつメソッドを定義する時に使用"""
                    self.add_item(person, *kv)

    def write(self, filename):
        """filename引数で指定されたファイルに辞書dicの内容を書き出す
        """
        g = open(filename, 'w')
        dic = self.dic
        person = ''
        for (p, attr) in sorted(dic.keys()):
            if person == '':
                g.write('*%s\n' % p)
            elif person != p:
                g.write('\n*%s\n' % p)
            person = p
            g.write('%s:' % attr)
            g.write(','.join(dic[p, attr]))
            g.write('\n')
        g.close()

    def __str__(self):
        """オブジェクトを print() に渡した際は、特殊メソッドの __str__() が
        呼ばれることになっている。ここでは辞書dic の内容を編集表示している。"""
        dic = self.dic
        s = ''
        for (p, attr) in sorted(dic.keys()):
           s += '%sさんの%sは: %s\n' % (p, attr, ','.join(dic[p, attr]))
        return s

def _main():
    """インスタンス生成。クラス名を関数と見立てて呼び出す
    p が返ってきた時点で __init__() の呼び出しは完了している"""
    p = people()

    p.read('profiles.txt')  # メソッドは、インスタンス変数.メソッド名で呼び出す
    print p                 # 自動的に__str__()が呼び出される
    prink(p.__str__())      # 明示的に__str__()を呼び出す
    p.add_item('ジャネット', '正体', 'サイボーグ')
    p.write('profiles4.txt')

if __name__ == '__main__' : _main()
# coding:utf-8

from people import people, prink  # from モジュール名 import クラス名、メソッド名

"""class 派生先クラス(派生元クラス)"""
class peoplex(people):

    uniq_list = ['出身', '年齢', '身長']    # クラス変数

    def __init__(self):
        """pythonの場合、派生元クラスの__init__()が暗黙的に呼び出される
        仕組みはないので、必要に応じて明示的に呼び出す必要がある"""
        people.__init__(self)

    def add_item(self, person, key, value):
        """派生したクラス(peoplex)で派生元のクラス(people)のメソッドを上書き(オーバーライド)
        peopleクラスとの違いは、クラス変数uniq_listに含まれる項目については重複した挿入を許さ
        ないところ"""
        dic = self.dic
        if (person, key) not in dic:
            dic[person, key] = []

        """メソッドからクラス変数にアクセスするには self.__class__.~の形で使う"""
        if key in self.__class__.uniq_list:
            if len(dic[person, key]) > 1:
                raise ValueError    # 意図的に例外を発生させる

            if len(dic[person, key]) == 1:
                if value == dic[person, key][0]:
                    """同じ値が指定された場合はスキップ"""
                    pass
                else:
                    """別の値が設定された場合は例外を飛ばす"""
                    raise ValueError, \
                    "(person, key, value)=(%s,%s,%s)" % (person, key, value)
            else: # len == 0
                """初めての値の場合はリストに挿入"""
                dic[person, key].append(value)

        else:
            """uniq_listにないキーの場合は普通に挿入"""
            if value not in dic[person, key]:
                dic[person, key].append(value)

    def __str__(self):
        """オーバーライドのメソッド。peopleクラスとの違いは、人物名を一度だけ表示する"""
        dic = self.dic
        s = ''
        person = ''
        for (p, attr) in sorted(dic.keys()):
           if person == '' or person != p:
               s += '%sさんの情報:\n' % p
           s += '\t%sは:%s\n' % (attr, ','.join(dic[p, attr]))
           person = p
        return s

def _main():
    x = peoplex()
    x.read('profiles5.txt')
    x.read('profiles6.txt')

    print x
    prink(x.__str__())

if __name__ == '__main__' : _main()


実行結果

$ python people.py
ゆかりさんの好物は: おにぎり
ゆかりさんの年齢は: 15
ゆかりさんの性格は: 女
ハリーさんの出身は: アイダホ
ハリーさんの年齢は: 20
ハリーさんの性格は: 神経質
ハリーさんの髪型は: よこわけ
太郎さんの出身は: 北海道
太郎さんの年齢は: 18
太郎さんの性格は: おっとり
太郎さんの身長は: 170

ゆかりさんの好物は: おにぎり
ゆかりさんの年齢は: 15
ゆかりさんの性格は: 女
ハリーさんの出身は: アイダホ
ハリーさんの年齢は: 20
ハリーさんの性格は: 神経質
ハリーさんの髪型は: よこわけ
太郎さんの出身は: 北海道
太郎さんの年齢は: 18
太郎さんの性格は: おっとり
太郎さんの身長は: 170

$ python peoplex0.py
太郎さんの情報:
        出身は:硫黄島
        好物は:パイン
        年齢は:20
        性格は:おっとり
        身長は:170
次郎さんの情報:
        出身は:鳥取
        年齢は:10
        性格は:神経質,やさしい

太郎さんの情報:
        出身は:硫黄島
        好物は:パイン
        年齢は:20
        性格は:おっとり
        身長は:170
次郎さんの情報:
        出身は:鳥取
        年齢は:10
        性格は:神経質,やさしい



バージョンアップ

参考先