第4回Python文法詳解を詳解する会に参加した。講師である石本さん、会場である(株)クロス・マーケティング様には感謝を申し上げたい。初台は大学時代通過するだけの駅で初めて降りた。なんだかお洒落なビルであった。 折角なので、記録したメモを公開したい。 なお、私は当日伊豆大島土産の青いTシャツを着て会議室の中央に座っていた。このご時勢にノートパソコンではなく紙のノートに万年筆というスタイルであった。
Python文法詳解を詳解する会 #4
5章:ステートメント
if文
- 条件式はブール式以外でもOK。
- 何もしないが文法的に空白が許されない場合は
passを使う。
while文
else節がある。break文が実行されなかった場合にelseブロックを実行する。
for文
- 変数にイテラブルオブジェクト(P.24, P.258)から取り出した要素を先頭から代入し
forブロック内の処理を実行 - 変数への代入にはアンパック、
*argsが使える。
L = [(1, 2), (3, 4, 5), (6, 7, 8, 9)] for car, *cdr in L: print(car, cdr)
1 [2] 3 [4, 5] 6 [7, 8, 9]
for文にもelse節がある。forループがbreakで中断されずに終了した場合のみelse節が実行される。
range 函数
rangeオブジェクトはイテレータではない。
ls = range(3) for x in ls: print(x) for y in ls: print(y)
0 1 2 0 1 2
(記録者注)イテレータの場合の動作。iter函数でイテレータを返す。
it = iter(range(3)) for x in ls: print(x) for y in ls: print(y)
0 1 2
enumrate 函数
L = ['one', 'two', 'three'] for num, value in enumerate(L, 1): print(num, value)
1 one 2 two 3 three
例外処理
- Pythonは例外をよく使う。
try,except,else,finallyからなる。elseブロックはtryブロックで例外は発生しなかったときに実行される。except節で指定した以外の例外が発生した場合に実行されるわけではない。except...asで指定した変数はハンドラを抜けると削除される(Py3)。メモリリーク対策のため。finallyブロックはexceptやelseブロックのあとに実行される。- CPythonでは
finallyブロックではcontinue文を実行できない。言語仕様では定義されていない。 finallyブロックでreturn文を実行すると例外を握りつぶす。BaseExceptionから直接派生している例外をアプリケーション側では無視してはいけない。Exceptionまたはその派生の例外をexceptで指定する。
raise文
raise文には送出する例外オブジェクト、または例外オブジェクトの型を指定する。- 例外オブジェクトを指定せずに
raise文を実行すると処理中の例外オブジェクトがそのまま再送出される。 - 例外処理中に例外が発生した場合、例外を連結して両方送出する。これはPy3で導入された。 Py2では上書きされていた。
トレースバックオブジェクト
with_traceback()メソッドで元の例外オブジェクトのトレースバックを新しい例外オブジェクトに設定できる。 あまり使う機会がない。
assert文
- Python起動時に最適化オプション(
-Oまたは-OO)を指定すると実行されない。
with文
- オブジェクトによって動作が異なる。
with文に対応したオブジェクトをコンテキストマネージャと呼ぶ。- カンマで複数のコンテキストマネージャを指定することが出来る。
6章:関数
関数定義
- 函数内で定義した変数及びインポートしたモジュールは函数内のみ有効
return文が実行されないまたは省略した場合、函数はNoneを返す。 (記録者注: Rubyだと最後に評価した式の値を返す、だった気がした。)- 函数定義は
ifブロック内に記述することも出来る。条件によって中身が異なる函数が定義できる。 - 可変長引数
*args
def spam(ham, egg, *args): print('ham={}, egg={}, args={}'.format(ham, egg, args)) spam(1, 2, 3, 4, 5)
ham=1, egg=2, args=(3, 4, 5)
- キーワード専用引数。
*argsのような*つきの引数の後に指定した引数は位置で指定することが出来ない。 キーワードで指定する必要がある。 引数リストに
*だけ指定すると、*よりも右側で指定した引数は必ずキーワード引数として指定しなければならない。デフォルト引数に更新可能オブジェクトを入れる場合には注意が必要。
def spam(ham=[]): ham.append(1) print(ham) spam() spam() spam()
[1] [1, 1] [1, 1, 1]
- デフォルト引数が作成されるのは函数オブジェクトを作成するタイミング。
for i in range(10): def spam(ham=[]): ham.append(1) print(ham) spam()
- 函数アノテーション。型チェック機能がPy3.5から導入されるかもしれない。
lambda式。式で函数オブジェクトを生成する。ブロックを含めることが出来ない。 Py3で削除されるかと思われたが生き残っている。
モジュールとパッケージ
- エンコーディングはUTF-8がデフォルト。
- モジュールのトップレベルで定義した変数はグローバルスコープに入る。
- 函数内で
global文を使うことでローカル変数ではなくグローバル変数として扱うことが出来る。 - グローバル変数は事前に定義する必要は無い。
from ... import ...でモジュールを指定する場合、__all__にシーケンスが定義してあれば__all__に含まれる名前のオブジェクトのみ、__all__が無い場合は名前の一文字目が_ではないオブジェクトがすべてインポートされる。- モジュールの検索パスは
sys.pathに指定されたものを検索する。 - ユーザのホームディレクトリにOS毎に特定のディレクトリを作成しておくと自動的に
sys.pathに追加される。 - zipファイルからもインポートできる。
- パス設定ファイルも利用できる。
virtualenvなどで利用されている。
パッケージ
- ディレクトリに
__init__.pyがある場合、パッケージとしてインポートできる。 - 同じパッケージ内にあるモジュールは相対インポートを指定できる。
Py3.3から名前空間パッケージが導入され、
__init__.pyが存在しなくてもsys.pathに登録されたディレクトリのサブディレクトリも名前空間パッケージとしてインポートできる。 (記録者注: Zopeにも同様の機能があるらしい。)モジュールの実行には以下3つの方法もある。
-mオプションでモジュール名を指定して実行__main__.pyを含むディレクトリを指定して実行- zipファイルを指定して実行
__main__モジュール
- 実行中のスクリプトの名前は
__name__に入っている。
if __name__ == '__main__': spam()
コンパイル済みモジュールファイル
- モジュールをインポートするとバイトコードにコンパイルしてから実行する。
- コンパイル済みモジュールは
__pycache__サブディレクトリに作成される。 - Py3.5で削除されるかもしれない。議論されている。 (了)
感想
初めて社外の勉強会に参加したがとても面白かった。普段Pythonの話なんてほとんどできないのでその反動もあるが本当に楽しかった。 ちょうどEffective Pythonの自家邦訳を進めている最中で函数のところはよく文法詳解を参照していたのだがそ、そうだったのか!ということもあった。 終了後のパブにもお邪魔させていただいた。興味深い話が多くこれまた楽しかった。見知らぬ人たちとお酒を飲みのも初めてであった。 懐が寂しくちゃんとつまみを提供できなかったのが悔やまれる。