FrontPage / Learning Programming / 2015 / 2nd Semester

Learning Programming

2015年後期 概要

目的
自然言語処理100本ノックを,Python の言語仕様,good parts,best practice,よくハマる罠などを確認しながらじっくり解く.
日時
月曜日 13:00-14:30
参加者
折田 (naho),横井 (yokoi),上村 (may-u),鈴木 (m-suzuki),ダワ (dava),ゼン,Diana (dianags)
TA
山口 (k.yamaguchi),佐々木 (aki-s),高橋(諒) (ryo-t),五十嵐 (igarashi)
問題
http://www.cl.ecei.tohoku.ac.jp/nlp100/
http://www.cl.ecei.tohoku.ac.jp/local/?nlp100-%CE%B2 (内部ページ)
回答
http://www.cl.ecei.tohoku.ac.jp/~igarashi/yuru_nlp/index.py (内部ページ)
/home/igarashi/yuru_nlp/{username}/ に「問題番号を0埋め3桁.py」(e.g. 000.py) を up
前期分: http://www.cl.ecei.tohoku.ac.jp/~takase/nlp100/index.py (内部ページ)

参考資料

  • 分からないことがあったら…
    • Python の言語仕様や「Python っぽい書き方」が知りたければ Python 関係の資料にあたる.
    • 「オブジェクト指向って何?」「型って何?」「スコープって何?」という疑問は,プログラミング全般に書かれている書籍や,別言語の参考書で解決できるかもしれない.
    • Linux コマンドの使い方や,バージョン管理ソフト(e.g. git), ターミナルマルチプレクサ(e.g. tmux), パッケージ管理ソフト(e.g. homebrew), エディタ(e.g. vim)などの使い方で困っているならそれ専用の資料に当たる.
    • 何について困っているのか考えましょう.

Python

リファレンス

リンク集

情報を取り出すための基本コマンド

  • `help(command)` -> docstring がページャで開かれる.`command?` でも print されるが,場合によっては短縮版.
  • `dir(obj)` -> オブジェクトに紐づくプロパティ名やメソッド名の一覧が表示される.
  • `type(obj)` -> オブジェクトの型が表示される.

導入・全体像など

Good Parts

  • 『Python Cookbook』
    • 日本語版は, 版が古く, かついくつかの章が省略されている
  • 『エキスパートPythonプログラミング』
    • Good Parts および Python ちっくなソフトウェア工学

コーディング規約・スタイルガイド

Tools

  • Jupyter
    • GUI インタラクティブインタプリタ, 兼 markdown メモ, 兼 図表ビューア
    • スピーディにプログラムの第1稿を作る際の必須ツール
    • matplotlib (seaborn) との相性も良く, 実験でも大変便利
  • Online Python Tutor
    • プログラムの動き (メモリが書きかわる様子) を視覚化

2.x 系? 3.x 系?

misc

プログラミング全般,各種パラダイム

  • 『プログラマの考え方がおもしろいほど身につく本』(目次)
  • 『コーディングを支える技術』(目次)
  • 『リーダブルコード』

Linux,各種ツール

  • 全般
    • 『新しい Linux の教科書』
  • シェル
    • 『zsh の本』
  • バージョン管理
    • 『GitHub 実践入門』

予定・記録

#07 2015/12/07(Mon) 13:15-14:50

参加者

  • 横井,上村,鈴木,ダワ
  • (TA) 山口,佐々木,高橋

解いた問題

  • 020-023 (4問)

Tips

  • `dict.get(k[, d])`: D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
    • `dict[key]` の場合,dict に key が存在しない場合 KeyError で落ちる
  • `dict.setdefault(k[, d])`: D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
    • 挙動は 'get or set default value'
    • 可読性を落とすので dict.setdefault は使わない
    • dict に初期値を与えたい場合は collections.defaultdict を使う

Tips (JSON)

  • `import json`
    • `json.load(fp)` -> a Python object
    • `json.loads(s)` -> a Python object (s: str or unicode)
      • よきに strip() してくれる?
      • 基本的に文字列は unicode 型に.
      • `json.loads(' {"foo":"baa"} ')` -> `{u'foo': u'baa'}`
  • `$ jq` (shell)
    • `-r`: output raw strings, not JSON texts;
      • クォートされた文字列を生の文字列にする 例えば '\n' で改行される
      • クォートされた文字列中に改行を含むデータは `-r` せず,クォートされたままの方が扱いやすい
      • たとえば tweet データ
      • Shell で無理に処理しない

Tips (正規表現)

  • references
  • pattern
    • 基本的に `r` を付ける(`r'exp'`)
    • unicode 文字列の場合は `ur'exp'`
      • utf-8 の文書に対して ascii の文字列で match させたい場合は,とくに u をつけなくてもOK.別の文字列を表すバイト列に ascii の文字列が部分列として含まれることはない(ように設計されている)
      • sjis だと↑の問題が起き得る.
  • match
    • **p.match は bad parts っぽい**
    • p.match は行頭限定の p.search.はじめから pattern に `^` を入れて検索すれば良さそう.

Tips (シェル芸)

#06 2015/11/30(Mon) 13:10-14:10

参加者

  • 折田,横井,上村,鈴木,ダワ
  • (TA) 山口,高橋

解いた問題

  • 017-019 (3問)

#05 2015/11/16(Mon) 13:10-15:05

参加者

  • 横井,ダワ
  • (TA) 山口,佐々木,高橋

解いた問題

  • 014-016 (3問)

Tips

  • seq[:n] で n>len(seq) だった場合もよきに計らってくれる (末尾以後の無視され,seq[:] が返る)
    • ファイルオブジェクトの確保
      • sys.stdin の __exit__() メソッド(ある!)を呼び出す必要は特にないので, `with sys.stdin as f` は不要
  • 014
  • pandas
    • jupyter との共用が前提.interactive に表の状態を可視化できる.(セルの最後の行の評価結果がデータフレームであれば,そのまま見やすく出力される)
  • any, all

Tips (shell command の実行)

>>> import subprocess
>>> import shlex
>>> cmd = readline()
wc -l hightemp.txt
  • 結果を受取る: `subprocess.check_output(shlex.split(cmd))`

#04 2015/11/09(Mon) 13:00-14:40

参加者

  • 横井,上村,鈴木,佐藤,ダワ,Diana
  • (TA) 山口,佐々木,高橋

解いた問題

  • 009-013 (5問)

Tips

  • ファイル末尾の改行:
  • list(文字列) → 文字のリスト
    • `list('hoge')` -> `['h','o','g','e']`
  • スライスはコピーを返す.
    • `x=range(5); random.shuffle(x[:])`: x は shuffle されない.
  • str.split() で separator を省略すると,連続したホワイトスペースがひとつのセパレータと見なされる.cf. separator として `' '` (ひとつの空白) を指定
    • `'foo baa'.split()` -> `['foo','baa']`
    • `'foo baa'.split(' ')` -> `['foo','','baa']`
  • import 式: e.g., `__import__('random')`
    • グローバル領域の名前「モジュール名」を汚さない. (function スタックには積まれるので再利用性が下がりすぎることはない?)
    • lambda 式などで使い捨てするか,別の特定の変数に代入して使う?
    • ミドルウェアのバージョン違いを呼び出したいなど,モジュール名を動的に指定したいときにも便利.
    • `import somemodule as sm` と `sm = __import__('somemodule')` は等価?
  • random
    • random.shuffle(seq) は seq 自体を書き換える.値は返さない?
    • `random.sample(population, k)`: 母集団 (population) から k 個の標本を非復元抽出 (重複なしの sampling) をして結果のリストを返す
    • 標準ライブラリの random よりも numpy.random の方が偏りが少ないので,特に数値計算における乱数生成においては numpy.random を用いるべき (python/numpy - 機械学習の「朱鷺の杜Wiki」)
  • 基本的には generator 式の方が explicit なリストを作るよりも時間計算量も空間計算量も有利.
    • ただし,str のリストを join する場合は、はじめからリストにした方が速い.
  • `sorted(list, key=f)` f は list の要素から実数への関数.x を f(x) をキーに昇順に並べ直したリストを返す.
    • e.g., `sorted([['a',1],['b',3],['c',2]], key=(lambda x:x[1]))` -> `[['a', 1], ['c', 2], ['b', 3]]`

Tips (入出力)

  • ファイルオブジェクトの確保
    • 標準入力: `import sys; f = sys.stdin` (同様に `sys.stdout`, `sys.stderr` で標準出力,標準エラー出力が取り出せる)
    • open: `with open(path, 'r') as f:`
      • 'r': read, 'w': write, 'a': 追加書き込み
      • 'b': binary (これは,テキストファイルとバイナリファイルが区別される環境 e.g., Windows でのみ気にするオプション)
    • with exp as x: とすると,exp の評価結果のオブジェクトが x に代入され,with ブロックを抜ける際に obj.__exit__() が実行され,よきにはからってくれる (ファイルの場合は close してくれる)
    • ファイル path を複数指定して cat したものを open: `import fileinput; f = fileinput.input(['foo.txt', 'baa.txt'])`
    • コマンドライン引数から与えたファイルの集合 (sys.argv[1:]) を cat したものを open: `import fileinput; f = fileinput.input()`
  • 読み込み (改行コードも取得される)
    • 1行ずつ読み込み: `f.readline()`
    • 1行ずつ読み込み: `for l in f`
    • 全体を読み込み: `f.read()`
    • 全ての行を読み込んで配列に確保: `arr = f.readlines()` (ファイルが小さいとわかっているとき以外非推奨)
  • 書き出し
    • 標準出力に書き出し(末尾に改行を挿入する): `print 'foo'`
    • 標準出力に書き出し(末尾に改行を挿入しない): `print 'foo',` (余計な空白も挿入されない)
    • 標準出力に書き出し(末尾に改行を挿入しない): `sys.stdout.write('foo')` (None を返す)
    • ファイルに書き出し(末尾に改行を挿入しない): `f.write('foo')`
    • ファイルに書き出し(末尾に改行を挿入する): `print >> f, 'foo'`
    • ファイルに書き出し(末尾に改行を挿入しない): `print >> f, 'foo',`
  • プロンプトから読み込み
    • `s = raw_input()` (改行コード入力まで)

Tips (Shell)

  • <(command) で command の出力がファイル扱いになる
    • e.g., `$ diff <(./hoge) <(./fuga)`
    • cf. パイプでは標準出力→標準入力でしか渡せない (前処理側コマンドの出力を次処理側コマンドのコマンドライン引数として渡せない)
  • 特にシェル芸をしたい場合,OS X (BSD 系) のコマンド群を GNU/Linux 系の (ググった場合に大抵出てくる方の) コマンド群に置き換えるために,homebrew で gawk, gsed, gtar, coreutils (ls, cd などが含まれる) をまとめてインストール推奨

#03 2015/11/02(Mon) 13:00-14:30

参加者

  • 折田,横井,上村,ダワ
  • (TA) 山口,佐々木,高橋,鈴木

解いた問題

  • 005-008 (4問)

Tips

  • 利用しない変数はアンダースコアそのものないしアンダースコアからはじまる変数名を用いることが多い.
    • e.g. 回す回数にのみ興味があり,インデックスには興味がない for 文: `for _ in xrange(3): print('foo')`
    • `_` は ML 系のようにワイルドカードを表すわけではない.
  • 基本的な演算に対して,True は 1,False は 0 として振舞う.
    • http://docs.python.jp/2/reference/datamodel.html
      ブール型は整数のサブタイプで、ほとんどの演算コンテキストにおいてブール型値はそれぞれ 0 または 1 のように振舞います。
      ただし、文字列に変換されたときのみ、それぞれ文字列 "False" および "True" が返されます。
    • `[e0, e1][cond]`: 評価結果は三項演算子と等価.ゴルファーの定石らしい.ただし常に `e0, e1` がともに評価され無駄.文字数削減以外のメリットはない.
  • メソッドや関数を `()` を付けずに変数に代入すると,変数が呼び出し可能オブジェクトとなる.
    • e.g. `f='{}時の{}は{}'.format` `print f(12,'気温',22.4)'`
    • lambda 式のように扱える.
  • Python の `and`,`or` の挙動
    • `e1 or e2` は `e1` の評価結果が真(と見なせる)とき `e1` の 評価結果そのもの ,偽のとき `e2` の 評価結果そのもの を返す
      • `2 or 0` -> 2
      • cf. C言語: 評価を `e1` 止める点は同じだが,返すのは `e1` の(cond としての,bool としての)評価結果 \in {0, 1}
    • `e1 and e2` は `e1` の評価結果が偽(と見なせる)とき `e1` の 評価結果そのもの ,真のとき `e2` の 評価結果そのもの を返す
  • def の引数の可変長化
    • `*`ではじまるパラメータは可変長の引数を取り tuple として関数に取り込む
      • `def f(*args): print args; f(1,2,'foo')` -> (1,2,'foo')
    • `**` ではじまるパラメータは可変長の引数を取り dict として関数に取り込む
      • `def f(**args): print args; f(x=0,y=1)` -> {'x': 0, 'y': 1}
    • https://docs.python.org/2.7/reference/compound_stmts.html#function-definitions

Tips (文字コード (Python 2.x))

  • ソースコードのエンコーディング
    • 1行目 or 2行目に以下のマジックコメントを指定することで,ソースファイルを(実体はバイト列)をどの文字コードで解釈すべきなのかを python の処理系に教える
      • `# -*- coding: utf-8 -*-`
      • エディタの設定やシェルのロケール($LANG)に合わせておけば良い.(すべて utf-8 にしておけば良い)
  • str 型
    • str 型はバイト列そのもの
    • `s = 'ほげ'` // '\xe3\x81\xbb\xe3\x81\x92'
    • file から read する際,バイト列(=str 型)が読み込まれる.
    • file へはバイト列(=str 型)を write する.
  • unicode 型
    • `u = u'ほげ'` // u'\u307b\u3052'
    • unicode で規定された各「文字」を区別するための内部表現
    • (非 ascii 文字列に対する)比較や文字列長の計算などが「直感的に」行える.
    • 非 ascii 文字が入ったファイルはなるべく早めに unicode 型にして処理する.
    • ただし unicode 型は処理が遅い.unicode 型にする必要がなければ,また,速度がきになる場合は,str 型のまま(バイト列のまま)処理する.
  • str 型(バイト列)と unicode 型の相互変換
    • `s.decode('utf-8')` -> unicode 型
    • `u.encode('utf-8')` -> str 型
      • `codecs.endcode(u, 'utf-8')` との違い?
    • encode()/decode() 時のデフォルトの encoding (文字コード)は sys.getdefaultencoding() に従う.
    • sys.getdefaultencoding() の変更方法は後述.
    • ascii 文字(列)は処理系がよきに計らってくれる
      • `'a' == u'a'` -> `True`
  • ファイルの読み込み
    • `open(path, 'r')` -> バイト列(str 型)として読み込み.
    • `import codecs` `codecs.open(path, 'r', 'utf-8')` -> unicode 型で読み込み.
  • unicode 型を直接 print
    • sys.stdout.encoding に従って encode される
    • sys.stdout.encoding 設定方法は後述.
  • unicode 型をファイルに直接 write(),または,print だがパイプで別プロセスに流す
    • sys.getdefaultencoding() に従う.
  • sys.setdefaultencoding の設定
    • ソースコード中に以下の3行を追加するか
      import sys
      reload(sys)
      sys.setdefaultencoding('utf-8')
    • sitecustomize.py を編集し以下の2行を追加する.
      import sys
      sys.setdefaultencoding("utf-8")
  • sys.stdout.encoding の設定
    • `sys.stdout = codecs.getwriter('utf_8')(sys.stdout)` で変更可.
    • 指定がなければ&ターミナルエミュレータに吐き出す場合は シェルのロケール($LANG)が参照される.
    • 次プロセスにパイプで繋ぐ場合は sys.setdefaultencoding が参照される.
    • とりあえず sys.setdefaultencoding をセットしておくべし.
  • 我々に「見えて」いるのは,str 型や unicode 型がバイト列に変換されたものをシェルやエディタが解釈した後の「文字列」であることに注意.

#02 2015/10/26(Mon) 13:00-14:45

参加者

  • 折田,横井,上村,ダワ,Diana
  • (TA) 佐々木,高橋,五十嵐,鈴木

解いた問題

  • 002-004

Tips

  • 文字列のクォーテーション
  • docstring
    • `"""` に続く1行目が関数の要約解説
    • 空行をひとつ挟んで,残りで詳細を書く
  • zip
    • 複数のシーケンスからタプルのリストを作る: zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
    • 引数のシーケンス長が異なる場合は,一番短いものに合わせられる zip([1,2,3],[4,5]) -> [(1, 4), (2, 5)]
  • str.join の引数は,string が返ってくる iterable なオブジェクトならなんでも良い S.join(iterable) -> string
    • '_'.join('hoge') -> 'h_o_g_e'
    • ''.join( ('a', 'b', 'c') ) -> 'abc'
  • 文字列は immutable なので、`s += ...` の連発は、都度メモリ確保が発生して遅い&無駄.list に append → join にすべし.
    • → と思いきや誤差っぽい.(cf. JavaScript) 文字列長が極端に長ければ有用かもしれないが,どういうシチュエーション?
  • 計算量関連
    • set は x in s が早い (average: O(1))
      • set, dict は hash table が作られる.
      • set の要素および dict の key には hashable (≒immutable ?) なオブジェクトしか入れられない.
      • たとえば set の要素に list を入れることはできない.
    • list は(一般的なプログラミング言語で使う意味での)配列.連続したメモリ領域に書き込まれ,get が高速 (O(1))
    • (一般的なプログラミング言語で使う意味での)「リスト(cons cell 型のデータ構造)」を作りたければ,多重タプルで無理矢理実装できなくもない `(a, (b, (c, d)))`
    • TimeComplexity - Python Wiki
  • a, b, c は基本的に (a, b, c) の意 (syntax sugar?)
  • クラスのメソッドの第一引数に self をつけられるのは,クラスそのものの public method として呼び出した場合とインスタンスのメソッドを呼び出した場合の挙動を一致させたい(ないし一度に定義したい)という設計思想も入っている
    • `set.union(X,Y)` == `X.union(Y)` (第一引数が省略されている)
  • 文字列処理
    • str.split(): 任意のセパレータ文字列(初期値はスペース, タブ, 改行)で分割→リストに保存
    • 正規表現はスピードのボトルネックになるので極力使わない
      • `r'[]'` の中の「ピリオドにマッチ」を表す `.` はエスケープ不要
      • `[]` の中では先頭の `^` および先頭以外の `[`, `]`, `-` 以外はエスケープ不要
    • str.strip() 引数に入れた文字列を文字の集合と見て、文字列の両端に存在する該当文字を削除 '.,.ho..ge,,'.strip(',.') -> 'ho..ge'
      • 一方からだけ削りたい場合は rstlip, lstrip
    • 引数を与えない場合、各種ホワイトスペース ('\t', ' ', '\n', など) が取り除かれる.
      • 内側も削る場合は replace
  • 内包表記 (comprehensions)
    • dict comprehensions `{k:v for ...}`
  • generator
    • `(f(x) for x in iterable)` は generator expressions (ジェネレータ式)
    • generator は「遅延評価されるストリーム」の作成方法のひとつ
      • iterator はプロトコル.「next() メソッドを持ってね,こういう風に動作してね」というノリだけ定められている.
      • itertools.iterator という抽象クラスは用意されているが,実装上は独自型を作ってコンストラクタを充てることが多い?
      • docstring には↑を使う?
      • 「遅延評価されるストリーム」を作りたければ,1. iterator 的なクラスを作る,2. generator 式,3. generator 関数(def/yield)のいずれか
  • dictionary を value でソート: sorted(d.iteritems(), key=(lambda x: x[1]))
    • 全体としてリストを返す
    • iteritems(): (k,v) のリストの iterator を返す
  • fold, reduce
    • sum([('a','b'),('c','d')], ()) は,おそらく,`()`(空タプル)を初期値として `+` で left fold.
    • reduce は left fold.
    • reduce(func, seq, init) で init を与えない場合は,seq の 0 番目が init 扱いになり,func(seq[0], seq[1]) から計算がはじまる.

#01 2015/10/19(Mon) 14:40-17:00

参加者

  • 横井,上村,ダワ,Diana,ゼン
  • (TA) 山口,佐々木,高橋,五十嵐

Tutorial (佐々木)

  • 環境構築(environmental construction) slide(ja), slide(en)
    • 研究室の計算機環境,サーバへのログイン,Python の実行,virtualenv,Jupyter
    • (付録) tmux, linux コマンド
  • コードのアップロード方法(how to upload your source codes) slide(ja), slide(en)

解いた問題

  • 000, 001

Tips

  • インデントは4スペース (ソフトタブ)
    • エディタで Tab キーを押したときに '\t' ではなく半角スペース×4によるインデントが挿入されるように各自設定
  • 変数名関数名を,キーワードや組み込みの関数名とぶつけない
  • 組み込みのメソッドや関数の仕様の確認方法
    • Python 2.7.10 documentation を読む
      • 困ったことがあったらまず公式ドキュメントを確認
    • Dash for OS X (documentation をローカルで読む.有償ソフト.)
    • interactive shell (ipython) 上で `help(command)`, `command?` (e.g. `str.join?`)
    • Jupyter 上でメソッドにカーソルを合わせて Shift+Tab
  • `dir()` : module, class, object に紐づく attribute (プロパティ,メソッド) の一覧を表示.
  • `type()`: “型” を表示.
  • tuple は immutable
    • オブジェクト自体が mutable/immutable なことと,そのオブジェクトを入れた変数が再代入可能/不可能なことを混同しない.
      In [1]: a = (1,2)
      In [2]: b = (3,4)
      In [3]: c = a
      In [4]: a += b # a に新しいオブジェクト (1,2)+(3,4) = (1,2,3,4) を再代入
      In [5]: a
      Out[5]: (1, 2, 3, 4)
      In [6]: c
      Out[6]: (1, 2) # c が指すメモリ領域は [1] で確保されたもの
  • enumerate(): list を添え字付きで走査するときに便利
  • range はリストそのもの, xrange はイテレータ (のようなもの, xrange 型オブジェクト) を返す.
    • リストそのものが欲しい場合以外, xrange を使えば良い.
    • 3系では range の挙動が 2系の xrange と同様?
  • 代入は文. 式ではない. (値を返さない)
    • `y = x = 1` は valid だが, C言語のように 右結合的に順に評価 (`y = (x = 1)`) しているわけではなく, `y = x = a` という気泡が用意されている (実際, Python で `y = (x = 1)` はエラーする)
    • なお比較演算子も同様の記法がサポートされている e.g. `0 < x < 5` (これは `0 < x and x < 5` と等価. ただし `x` の評価回数で損)
  • ソースファイルのエンコード宣言 (マジックコメント?): `# -*- coding: utf-8 -*-`
    • `-*-` をつけておくと Emacs フレンドリー?
  • ドキュメンテーション文字列 (docstring) は reStructuredText 形式で書く

過去の記録


© Inui-Suzuki Laboratory 2010-2018 All rights reserved.
Recent Changes
2020-06-25 2020-06-17 2020-06-16 2020-06-10 2020-06-08 2020-06-01 2020-04-10 2020-04-02 2020-02-22 2019-06-07 2019-06-06 2019-05-23 2019-04-19 2019-04-08 2019-04-07 2019-04-03 2019-04-01 2019-03-08 2019-03-07 2019-03-01 2019-02-28 2019-02-15 2019-02-14 2019-02-13 2019-02-12 2019-02-08 2019-02-07 2019-02-06 2019-02-05 2019-02-04 2019-02-01 2019-01-31 2019-01-30 2019-01-29 2019-01-28 2019-01-26 2019-01-25 2019-01-24 2019-01-23 2019-01-22 2019-01-19 2019-01-18 2019-01-17 2019-01-16 2019-01-15 2019-01-10 2019-01-09 2019-01-08 2019-01-07 2019-01-06 2019-01-04 2019-01-03 2018-12-27 2018-12-26 2018-12-25 2018-12-21 2018-12-20 2018-12-19 2018-12-18 2018-12-17 2018-12-16 2018-12-13 2018-12-12 2018-12-11 2018-12-10 2018-12-07 2018-12-06 2018-12-05 2018-12-04 2018-12-03 2018-12-02 2018-11-29 2018-11-28