Python演習
3. コレクションとファイル
前回の復習―string.split()
• string.split()
• 文字列を空白で分割し、文字列の「リスト」を返す
• 例: 'This is a pen.'.split() # ['This', 'is', 'a', 'pen.']
• では、この返り値の「リスト」とは?
• Fortranの配列のようなもの
• ただし配列の大きさを宣言する必要が無い
• そもそも変数の宣言自体がない
• list.append(obj)やlist.pop()で後から増減できる
• リストが使えると何が便利か
• データの集まりを表現することが可能
• string.split()はその1つの例になっている
• →今回:リストとその周辺(コレクション)
リスト
• リスト
• データの集まり(0から始まる)
• 存在しない添字には代入も参照もできない
• データの「系列」が入ることを想定
• [](リテラル)で作る
• x = [1, 2, 3] # [1, 2, 3]
• x = [] # []
• str.split()等リストを作る関数(メソッド)で作る
• x = 'This is a pen.'.split() # ['This', 'is', 'a', 'pen.']
• list()関数で作る
• x = list(range(5)) # [0, 1, 2, 3, 4]
リストの要素の参照と代入
• list[index]
• listのindex番目の要素を取得する
• list[start:end:step]
• 部分リストを作る(startは0から)
• endは最後の添字の次の番号
• stepを指定するとstepごとに要素を拾う
• stepが負の場合は後ろから読む
• 例
• [1, 2, 3, 4, 5][0] # 1 (第0要素)
• [1, 2, 3, 4, 5][0:3] # [1, 2, 3] (第0-3要素)
• [1, 2, 3, 4, 5][::2] # [1, 3, 5] (2つに1つ読む)
• [1, 2, 3, 4, 5][::-1] # [5, 4, 3, 2, 1] (逆順)
• [1, 2, 3, 4, 5][:] # [1, 2, 3, 4, 5] (リストの複製)
リストの操作1
• リストの操作
• list.append(x) # listにxを追加
• list.extend(x) # listにxを展開して追加
• list.pop() # listから末尾の要素を削除し返す
• list.pop(i) # listからi番目の要素を削除し返す
• 例
x = [1, 2, 3, 4] # リストを生成しxに代入
x.append(5) # [1, 2, 3, 4, 5]
x.extend([6, 7]) # [1, 2, 3, 4, 5, 6, 7]
tail = x.pop() # tail = 7, x = [1, 2, 3, 4, 5, 6]
head = x.pop(0) # head = 1, x = [2, 3, 4, 5, 6]
リストの操作2
• +と*
• list1 + list2 # list1とlist2を連結したリスト
• list * int # listをint回繰り返したリスト
• 例
• [1, 2] + [3, 4] # [1, 2, 3, 4]
• ['a', 'b'] * 3 # ['a', 'b', 'a', 'b', 'a', 'b']
• 関数(sorted(list)、len(list))
• sorted(list) # listをソートした配列を返す
• len(list) # listの要素数(末尾のindex+1)
• 例
• sorted([1, 2, 3, 4, 5]) # [5, 4, 3, 2, 1]
• len([1, 2, 4, 8, 16]) # 5 (4ではない)
注意―リストの複製
• 失敗例
x = [1, 2, 3, 4] # リストを作ってxに代入
y = x # yにxをコピー
x[0] = 2 # 「xの」先頭を変えたはずだけど…
print(y) # => [2, 2, 3, 4]
• 理由
• yには「リスト自体」がコピーされた
• 「要素」がコピーされたわけではない
• 正しい方法
• y = list(x) # listはリストを複製する
• y = x[:] # 部分リストを作っても複製される
注意―リストの複製(理由)
Fortranの配列: 箱そのものに名前がある
名前が違えば別の箱
x(1) x(2) x(3) x(n)
…
Pythonのリスト: 箱にタグを付けるだけ
コピーするとタグだけ増える
[0] [1] [2] [n-1]
…
発展―リスト内包表記
• [式 for x in 基になるリスト]
• 基になるリストの各要素に式を作用させたリスト
• [式 for x in 基になるリスト if 条件]
• 元になる集合で条件を満たす各要素について
• 式を作用させたリストを作る
• 例
• [x * x for x in [0, 1, 2, 3, 4]] # [0, 1, 4, 9, 16]
• [x for x in [0, 1, 2] if x % 2 == 0] # [0, 2]
リストのリスト
• リストの中身
• リストの中には何でも代入可能
• リストの中にリストを代入してもよい
• →多次元配列の代用
• 例: 3x3の配列を作る
• matrix = [[0]*3 for i in range(3)] # 配列の作成
• matrix[0][0] = 1 # 成分の代入
• print(matrix[0][0]) # 成分の表示
• 注意
• [0]*3は長さ3の配列を作る([]は第0成分に代入不可)
• matrix[[0]*3]*3とすると各行が連動してしまう
• 参照は(matrix[0])[0]と解釈される(代入も同様)
リストの例ーコマンドライン引数
• コマンドライン引数とは
• コマンド実行時に後ろに続けて書く引数
• 例: vi test.py # test.pyがコマンドライン引数
• コマンドライン引数の取得 (要import sys)
• sys.argvでpython3に続く引数をリストとして取得
• パイプ(|)やリダイレクト(>)の後は含まれない
• 例(これはREPLではなくシェルで実行)
• echo 'import sys; print(sys.argv)' > argv.py
• python3 argv.py # => ['argv.py']
• python3 argv.py a b c # => ['argv.py', 'a', 'b', 'c']
• python3 argv.py | cat # => ['argv.py']
タプル
• タプル
• 一度作ったら変更できない (定数リスト)
• 参照はリストと同様 (例: (1, 2, 3)[0] # 1)
• 1要素のタプルは(1,)のようにカンマを付ける
• 変数の集まり=「構造」が入ることを想定
• (,)(リテラル)で作る
• x = (1,2,3) # (1, 2, 3)
• x = () # ()
• 複数の返り値を持つ関数を使う
• def get_tuple():
• return 1, 2, 3
• x = get_tuple(): # (1, 2, 3)
演習7―リストの操作 (REPL)
1. x = [1, 2, 3]を実行して下さい
2. y = xとz = x[:]を実行して下さい
3. x.append(4)を実行しx, y, zを表示して下さい
4. x.pop()を実行しx, y, zを表示して下さい
5. [25, 10, 5, 1]をソートして下さい
6. ['25', '10', '5', '1']をソートして下さい
辞書型
• 辞書型
• 配列と似ているが文字列(等)を添え字にできる
• 存在しない添字は参照できない
• 要素の並び順は不定
• 作り方
• z = {'key': val, …} # {}でキーと値のペアを書く
• 使い方
• z = {'H': 1, 'C': 6} # {'H': 1, 'C': 6}
• z['N'] = 7 # {'H': 1, 'C': 6, 'N': 7}
• print(z) # => {'H': 1, 'C': 6, 'N': 7}
• print(z['H']) # => 1
• print(z['O']) # KeyError
辞書型―操作
• 辞書型の操作
• dict.keys() キーのリストを返します
• dict.values() 値のリストを返します
• dict.items() tuple(キー, 値)のリストを返します
• key in dict dictにkeyがあるか調べます
• 例
x = {'spam': 1, 'ham': 2, 'egg': 3} # 辞書の作成
x.keys() # ['egg', 'ham', 'spam']
x.values() # [3, 2, 1]
x.items() # [('egg', 3), ('ham', 2), ('spam', 1)]
• 後で重要なユースケースを3つ示します
• 分類は一般的ではないので注意!!
辞書型―辞書的用法
• 目的とメリット
• 辞書=定数表を作る
• 参照するキーを変数にする
• if文による分岐が不要になる
• 例: 元素記号→原子番号変換
• z_tab = {'H': 1, 'C': 6, 'O': 8} # 原子番号の表
• sym = 'O' # 目的の元素の記号
• z = z_tab[sym] # 元素記号を逆引き
辞書型―構造体的用法
• 目的とメリット
• データの集まりをやり取りする(cf.タプル)
• 変数を使って生成し、決まったキーで参照
• タプルと違い、参照時に順序を気にしなくて良い
• 例: 球の半径、面積、体積(関数の返り値)
def ball(r):
pi = 3.1415926535897932384
return {'rad': r, 'area': 4*pi*r*r, 'vol': 4*pi*r*r*r/3}
辞書型―動的変数用法
• 目的とメリット
• イメージ:変数名を動的に決める
• キーを変数にして、逐次代入する
• どんなキーがあるかが未知でも動く
• 例: 要素を数える
ar = list('Mississippi') # 1文字ずつのリスト
cnt = {} # 計数用ハッシュ
for ch in ar: # 1文字づつ処理
if ch in cnt: # すでに辞書にあれば
cnt[ch] += 1 # 1増やす
else: # 初めて見る文字なら
cnt[ch] = 1 # 1を代入(項目を作成)
print(cnt) # cntの中身を表示
演習8―辞書の取り扱い (REPL)
1. dict = {}により辞書を作って下さい
2. dictに'x': 3を追加し、表示して下さい
3. dictに'y': 4を追加し、表示して下さい
4. dictに'x': 5を追加し、表示して下さい
5. dictの'x'の値を1増やして下さい
6. dictの'z'の値を1増やそうとして下さい
ファイル操作―ファイルを開閉
• open(filename[, mode])
• ファイルを開いてファイルハンドラを返します
• modeは"r"で読み込み、"w"で書き込みモード
• modeを省略すると読み込みモードで開く
• file.close()
• fileを閉じます
• 標準入出力
• sys.stdin: 標準入力のファイルハンドラ
• sys.stdout: 標準出力のファイルハンドラ
• sys.stderr: 標準エラー出力のファイルハンドラ
• import sysが必要
• すでに開かれているのでそのまま使える
ファイル操作―読み込み
• for l in file: (基本形)
• fileから1行づつ読みlに順に代入する
• file.read()
• ファイルを全て読み込み、1つの文字列として返す
• file.readlines()
• ファイルを全て読み込み、文字列の配列で返す
• file.readline()
• ファイルを一行読み込み、文字列として返す
ファイル操作―書き出し
• 以下import sysは行われているとします
• 標準出力への書き出し
• print(obj) # objを表示
• sys.stdout.write(string) # stringを表示
• 標準エラー出力への書き出し
• print(obj, file=sys.stderr) # objを表示
• sys.stderr.write(string) # stringを表示
• ファイルへの書き出し
• f = open(filename, "w")
• print(obj, file=f) # objを表示
• f.write(string) # stringを表示
• f.close()
課題9―cpコマンド (file)
• cpコマンド
• file1をfile2にコピーする
• 実際にはfile1の中身をfile2に書いている
• 問題
• cpコマンドを実装して下さい
• オプションは実装しなくて構いません
• 注意
• この演習ではファイルを操作します
• 既存のファイルを壊さないようにして下さい
• ディレクトリを作ってその中で行うと少し安全です

Python勉強会3-コレクションとファイル

  • 1.
  • 2.
    前回の復習―string.split() • string.split() • 文字列を空白で分割し、文字列の「リスト」を返す •例: 'This is a pen.'.split() # ['This', 'is', 'a', 'pen.'] • では、この返り値の「リスト」とは? • Fortranの配列のようなもの • ただし配列の大きさを宣言する必要が無い • そもそも変数の宣言自体がない • list.append(obj)やlist.pop()で後から増減できる • リストが使えると何が便利か • データの集まりを表現することが可能 • string.split()はその1つの例になっている • →今回:リストとその周辺(コレクション)
  • 3.
    リスト • リスト • データの集まり(0から始まる) •存在しない添字には代入も参照もできない • データの「系列」が入ることを想定 • [](リテラル)で作る • x = [1, 2, 3] # [1, 2, 3] • x = [] # [] • str.split()等リストを作る関数(メソッド)で作る • x = 'This is a pen.'.split() # ['This', 'is', 'a', 'pen.'] • list()関数で作る • x = list(range(5)) # [0, 1, 2, 3, 4]
  • 4.
    リストの要素の参照と代入 • list[index] • listのindex番目の要素を取得する •list[start:end:step] • 部分リストを作る(startは0から) • endは最後の添字の次の番号 • stepを指定するとstepごとに要素を拾う • stepが負の場合は後ろから読む • 例 • [1, 2, 3, 4, 5][0] # 1 (第0要素) • [1, 2, 3, 4, 5][0:3] # [1, 2, 3] (第0-3要素) • [1, 2, 3, 4, 5][::2] # [1, 3, 5] (2つに1つ読む) • [1, 2, 3, 4, 5][::-1] # [5, 4, 3, 2, 1] (逆順) • [1, 2, 3, 4, 5][:] # [1, 2, 3, 4, 5] (リストの複製)
  • 5.
    リストの操作1 • リストの操作 • list.append(x)# listにxを追加 • list.extend(x) # listにxを展開して追加 • list.pop() # listから末尾の要素を削除し返す • list.pop(i) # listからi番目の要素を削除し返す • 例 x = [1, 2, 3, 4] # リストを生成しxに代入 x.append(5) # [1, 2, 3, 4, 5] x.extend([6, 7]) # [1, 2, 3, 4, 5, 6, 7] tail = x.pop() # tail = 7, x = [1, 2, 3, 4, 5, 6] head = x.pop(0) # head = 1, x = [2, 3, 4, 5, 6]
  • 6.
    リストの操作2 • +と* • list1+ list2 # list1とlist2を連結したリスト • list * int # listをint回繰り返したリスト • 例 • [1, 2] + [3, 4] # [1, 2, 3, 4] • ['a', 'b'] * 3 # ['a', 'b', 'a', 'b', 'a', 'b'] • 関数(sorted(list)、len(list)) • sorted(list) # listをソートした配列を返す • len(list) # listの要素数(末尾のindex+1) • 例 • sorted([1, 2, 3, 4, 5]) # [5, 4, 3, 2, 1] • len([1, 2, 4, 8, 16]) # 5 (4ではない)
  • 7.
    注意―リストの複製 • 失敗例 x =[1, 2, 3, 4] # リストを作ってxに代入 y = x # yにxをコピー x[0] = 2 # 「xの」先頭を変えたはずだけど… print(y) # => [2, 2, 3, 4] • 理由 • yには「リスト自体」がコピーされた • 「要素」がコピーされたわけではない • 正しい方法 • y = list(x) # listはリストを複製する • y = x[:] # 部分リストを作っても複製される
  • 8.
    注意―リストの複製(理由) Fortranの配列: 箱そのものに名前がある 名前が違えば別の箱 x(1) x(2)x(3) x(n) … Pythonのリスト: 箱にタグを付けるだけ コピーするとタグだけ増える [0] [1] [2] [n-1] …
  • 9.
    発展―リスト内包表記 • [式 forx in 基になるリスト] • 基になるリストの各要素に式を作用させたリスト • [式 for x in 基になるリスト if 条件] • 元になる集合で条件を満たす各要素について • 式を作用させたリストを作る • 例 • [x * x for x in [0, 1, 2, 3, 4]] # [0, 1, 4, 9, 16] • [x for x in [0, 1, 2] if x % 2 == 0] # [0, 2]
  • 10.
    リストのリスト • リストの中身 • リストの中には何でも代入可能 •リストの中にリストを代入してもよい • →多次元配列の代用 • 例: 3x3の配列を作る • matrix = [[0]*3 for i in range(3)] # 配列の作成 • matrix[0][0] = 1 # 成分の代入 • print(matrix[0][0]) # 成分の表示 • 注意 • [0]*3は長さ3の配列を作る([]は第0成分に代入不可) • matrix[[0]*3]*3とすると各行が連動してしまう • 参照は(matrix[0])[0]と解釈される(代入も同様)
  • 11.
    リストの例ーコマンドライン引数 • コマンドライン引数とは • コマンド実行時に後ろに続けて書く引数 •例: vi test.py # test.pyがコマンドライン引数 • コマンドライン引数の取得 (要import sys) • sys.argvでpython3に続く引数をリストとして取得 • パイプ(|)やリダイレクト(>)の後は含まれない • 例(これはREPLではなくシェルで実行) • echo 'import sys; print(sys.argv)' > argv.py • python3 argv.py # => ['argv.py'] • python3 argv.py a b c # => ['argv.py', 'a', 'b', 'c'] • python3 argv.py | cat # => ['argv.py']
  • 12.
    タプル • タプル • 一度作ったら変更できない(定数リスト) • 参照はリストと同様 (例: (1, 2, 3)[0] # 1) • 1要素のタプルは(1,)のようにカンマを付ける • 変数の集まり=「構造」が入ることを想定 • (,)(リテラル)で作る • x = (1,2,3) # (1, 2, 3) • x = () # () • 複数の返り値を持つ関数を使う • def get_tuple(): • return 1, 2, 3 • x = get_tuple(): # (1, 2, 3)
  • 13.
    演習7―リストの操作 (REPL) 1. x= [1, 2, 3]を実行して下さい 2. y = xとz = x[:]を実行して下さい 3. x.append(4)を実行しx, y, zを表示して下さい 4. x.pop()を実行しx, y, zを表示して下さい 5. [25, 10, 5, 1]をソートして下さい 6. ['25', '10', '5', '1']をソートして下さい
  • 14.
    辞書型 • 辞書型 • 配列と似ているが文字列(等)を添え字にできる •存在しない添字は参照できない • 要素の並び順は不定 • 作り方 • z = {'key': val, …} # {}でキーと値のペアを書く • 使い方 • z = {'H': 1, 'C': 6} # {'H': 1, 'C': 6} • z['N'] = 7 # {'H': 1, 'C': 6, 'N': 7} • print(z) # => {'H': 1, 'C': 6, 'N': 7} • print(z['H']) # => 1 • print(z['O']) # KeyError
  • 15.
    辞書型―操作 • 辞書型の操作 • dict.keys()キーのリストを返します • dict.values() 値のリストを返します • dict.items() tuple(キー, 値)のリストを返します • key in dict dictにkeyがあるか調べます • 例 x = {'spam': 1, 'ham': 2, 'egg': 3} # 辞書の作成 x.keys() # ['egg', 'ham', 'spam'] x.values() # [3, 2, 1] x.items() # [('egg', 3), ('ham', 2), ('spam', 1)] • 後で重要なユースケースを3つ示します • 分類は一般的ではないので注意!!
  • 16.
    辞書型―辞書的用法 • 目的とメリット • 辞書=定数表を作る •参照するキーを変数にする • if文による分岐が不要になる • 例: 元素記号→原子番号変換 • z_tab = {'H': 1, 'C': 6, 'O': 8} # 原子番号の表 • sym = 'O' # 目的の元素の記号 • z = z_tab[sym] # 元素記号を逆引き
  • 17.
    辞書型―構造体的用法 • 目的とメリット • データの集まりをやり取りする(cf.タプル) •変数を使って生成し、決まったキーで参照 • タプルと違い、参照時に順序を気にしなくて良い • 例: 球の半径、面積、体積(関数の返り値) def ball(r): pi = 3.1415926535897932384 return {'rad': r, 'area': 4*pi*r*r, 'vol': 4*pi*r*r*r/3}
  • 18.
    辞書型―動的変数用法 • 目的とメリット • イメージ:変数名を動的に決める •キーを変数にして、逐次代入する • どんなキーがあるかが未知でも動く • 例: 要素を数える ar = list('Mississippi') # 1文字ずつのリスト cnt = {} # 計数用ハッシュ for ch in ar: # 1文字づつ処理 if ch in cnt: # すでに辞書にあれば cnt[ch] += 1 # 1増やす else: # 初めて見る文字なら cnt[ch] = 1 # 1を代入(項目を作成) print(cnt) # cntの中身を表示
  • 19.
    演習8―辞書の取り扱い (REPL) 1. dict= {}により辞書を作って下さい 2. dictに'x': 3を追加し、表示して下さい 3. dictに'y': 4を追加し、表示して下さい 4. dictに'x': 5を追加し、表示して下さい 5. dictの'x'の値を1増やして下さい 6. dictの'z'の値を1増やそうとして下さい
  • 20.
    ファイル操作―ファイルを開閉 • open(filename[, mode]) •ファイルを開いてファイルハンドラを返します • modeは"r"で読み込み、"w"で書き込みモード • modeを省略すると読み込みモードで開く • file.close() • fileを閉じます • 標準入出力 • sys.stdin: 標準入力のファイルハンドラ • sys.stdout: 標準出力のファイルハンドラ • sys.stderr: 標準エラー出力のファイルハンドラ • import sysが必要 • すでに開かれているのでそのまま使える
  • 21.
    ファイル操作―読み込み • for lin file: (基本形) • fileから1行づつ読みlに順に代入する • file.read() • ファイルを全て読み込み、1つの文字列として返す • file.readlines() • ファイルを全て読み込み、文字列の配列で返す • file.readline() • ファイルを一行読み込み、文字列として返す
  • 22.
    ファイル操作―書き出し • 以下import sysは行われているとします •標準出力への書き出し • print(obj) # objを表示 • sys.stdout.write(string) # stringを表示 • 標準エラー出力への書き出し • print(obj, file=sys.stderr) # objを表示 • sys.stderr.write(string) # stringを表示 • ファイルへの書き出し • f = open(filename, "w") • print(obj, file=f) # objを表示 • f.write(string) # stringを表示 • f.close()
  • 23.
    課題9―cpコマンド (file) • cpコマンド •file1をfile2にコピーする • 実際にはfile1の中身をfile2に書いている • 問題 • cpコマンドを実装して下さい • オプションは実装しなくて構いません • 注意 • この演習ではファイルを操作します • 既存のファイルを壊さないようにして下さい • ディレクトリを作ってその中で行うと少し安全です