今しがた紹介した while 文のほかに, Python は他の言語でおなじみの普通の制御フロー文を, 多少のひねりを伴いつつ備えている。
おそらく最もおなじみの文型は if 文である。 たとえば,
>>> x = int(raw_input("Please enter an integer: ")) >>> if x < 0: ... x = 0 ... print 'Negative changed to zero' ... elif x == 0: ... print 'Zero' ... elif x == 1: ... print 'Single' ... else: ... print 'More' ...
零個以上の elif 部があってもよい。 else 部を付けてもよい。 キーワード `elif' は `else if' をつづめたものであり, 過剰な段付けを避けるのに役立つ。 if ... elif ... elif ... 列は, 他の言語で見られる switch 文や case 文の代用品である。
Python の for 文は, 君が C や Pascal で慣れてきたかもしれないものとは少しばかり違う。 (Pascal のように) いつも数の等差数列上で繰返しをしたり, (C のように) 繰返しのステップと停止条件の両方の定義を利用者に任せたり するのではない。むしろ Python の for 文は, 任意の列 (リストや文字列) の各項目に対し, それらが列に現れる順序で,繰返しをする。 たとえば (なんのしゃれのつもりもないが),
>>> # いくつかの文字列の長さを測る: ... a = ['cat', 'window', 'defenestrate'] >>> for x in a: ... print x, len(x) ... cat 3 window 6 defenestrate 12
ループ内で繰返しの対象にしている列を書き換えることは安全ではない (この ことはリストのような変化可能 (mutable) な列型にだけ起こり得る)。 もしも,(たとえば特定の項目を二重化するなどで)繰返しの対象にしているリス トを書き換える必要があるならば,君はコピーに対して繰返しをしなくてはな らない。スライス記法はこれを特に手軽なものにしている。たとえば,
>>> for x in a[:]: # リスト全体のスライス・コピーを作る ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrate', 'cat', 'window', 'defenestrate']
もし数列上で繰返しをする必要があるなら, 組込み関数 range() が手頃だ。 これは等差数列からなるリストを生成する。
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
与えた終端は,生成されるリストには決して含まれない。
range(10)
は 10 個の値からなるリストを生成し,
その 10 個の値はそれぞれ,
ちょうど長さ 10 の列の各項目に対応する正当な添字になっている。
range を別の数から開始させることや,様々な増分 (負でも
よい -- これは `ステップ' とも呼ばれる) を指定することも可能である。
>>> range(5, 10) [5, 6, 7, 8, 9] >>> range(0, 10, 3) [0, 3, 6, 9] >>> range(-10, -100, -30) [-10, -40, -70]
列の添字の上で繰返しをするには, range() と len() を次のように組み合わせる。
>>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for i in range(len(a)): ... print i, a[i] ... 0 Mary 1 had 2 a 3 little 4 lamb
break 文は,C と同じく,それを取り囲む 最小の for または while ループの外へ脱出する。
continue 文は,これもまた C から借りてきたものであり, ループの次の繰返しへと続ける。
ループ文には else
節があってもよい。これは (for で) リストが
尽きてループが停止したとき,または (while で) 条件が偽になったときに
実行されるが,break 文でループが終了したときは実行されない。
このことを,素数を探す下記のループで例示する。
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, 'equals', x, '*', n/x ... break ... else: ... # 因数が見つからずにループが終了 ... print n, 'is a prime number' ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3
pass 文は何もしない。これは,文が構文上要求されているが, プログラムが何の動作も要求していないときに使われる。たとえば,
>>> while 1: ... pass # keyboard interrupt を busy-wait する ...
私たちは Fibonacci 級数を任意の限界まで書く関数を造ることができる。
>>> def fib(n): # n までのフィボナッチ級数を書く ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # 今しがた定義した関数を呼び出す: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
キーワード def は関数の定義 (definition) を導入する。 その後に関数の名前と,かっこで囲んだ仮引数の並びが必ず続く, 関数の本体を構成する文は,その次の行から,必ず段付けされて始まる。 関数本体の最初の文は文字列リテラルでもよい。 この文字列リテラルは関数の ドキュメンテーション文字列 (documentation string), つまり docstring となる。
docstring を使って,オンライン文書や印刷文書を自動生成したり, 利用者が対話的にコードを閲覧できるようにするツールがある。 君が書くコードに docstring を入れることは良い習慣だから, それを習いにするよう努めよう。
関数の実行 (execution) は,その関数のローカル変数のために使われる 新しい記号表 (symbol table) を導入する。 より正確にいえば,関数内のすべての変数代入は,値をローカル記号表へ格納する。 しかるに変数参照は,まずローカル記号表を調べ,次にグローバル記号表を調べ, そしてそれから組込み名の表を調べる。 したがって,関数の内部では,グローバル変数を参照することはできても, 直接それへ値を代入することは (global 文で名前を挙げない 限り) できない。
関数呼出しでの実引数は,呼出しの時,その関数のローカル記号表の中へ導入される。 このように引数は値渡し (call by value) で渡される (ここで 値 (value) とは常に オブジェクト参照 (object reference) である。 オブジェクトの値 (value of the object) ではない)4.1。 関数がほかの関数を呼び出すとき, 新しいローカル記号表がその呼出しのために造られる。
関数定義は関数名を現在の記号表の中へ導入する。 関数名の値は,インタープリタが利用者定義関数として認識する型をもつ。 この値をほかの名前へ代入してよい。 代入するとその名前も関数として使うことができる。 これは一般的な改名 (renaming) のからくりとして働く。
>>> fib <function object at 10042ed0> >>> f = fib >>> f(100) 1 1 2 3 5 8 13 21 34 55 89
君は fib
が関数 (function) でなく手続き (procedure) だと
異議を唱えるかもしれない。
Python では,C と同じく,手続きとは値を返さない関数にすぎない。
ただし,技術的に言えば,かなりつまらない値とはいえ,手続きも値を返している。
その値を None
という (これは組込み名である)。
もしも書く値が None
だけならば,
インタープリタは通常それを書くことを差し控える。
もしも君が本当にそれを見たいならば,このようにしてそれを見ることができる。
>>> print fib(0) None
Fibonacci 級数を印字するかわりにその数列を返す関数を書くことは簡単だ。
>>> def fib2(n): # n までのフィボナッチ級数を返す ... """Return a list containing the Fibonacci series up to n.""" ... result = [] ... a, b = 0, 1 ... while b < n: ... result.append(b) # 下記を見よ ... a, b = b, a+b ... return result ... >>> f100 = fib2(100) # 関数を呼び出す >>> f100 # 結果を書く [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
例によって,この例は Python の新しい機能を示している。
None
を返す。
手続きの終端から落っこちたときも None
を返す。
result.append(b)
は,
リスト・オブジェクト result
のメソッド (method) を呼び出す。
メソッドとはオブジェクトに「属している」関数であり,
obj.methodname
として指名される。
ここで obj
はなんらかのオブジェクト (これは式であってもよい) であり,
methodname
はそのオブジェクトの型によって定義されるメソッドの
名前である。定義されるメソッドは型によって様々である。
別々の型のメソッドならば,あいまいさを生ずることなく同じ名前にできる。
(このチュートリアルで後から論ずるように,クラス (class) を使えば,
君独自のオブジェクト型とメソッドを定義することが可能だ)。
例に示したメソッド append() は,リスト・オブジェクトに対して
定義されており,リストの終端に新しい要素を追加する。
この例では "result = result + [b]" と等価だが,より効率的である。
可変個数の引数をとる関数も定義できる。 三つの形式があり,それらは組み合わせ可能である。
その最も使える形式は,1個または複数の引数に対するデフォルト値の指定である。 これは定義された個数よりも少ない引数で呼び出せる関数を造る。
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while 1: ok = raw_input(prompt) if ok in ('y', 'ye', 'yes'): return 1 if ok in ('n', 'no', 'nop', 'nope'): return 0 retries = retries - 1 if retries < 0: raise IOError, 'refusenik user' print complaint
この関数は ask_ok('Do you really want to quit?')
のようにも,
ask_ok('OK to overwrite the file?', 2)
のようにも呼び出せる。
デフォルト値は,関数定義の時点で, その関数を定義するスコープの中で評価される。よって
i = 5 def f(arg=i): print arg i = 6 f()
は 5
を印字する。
重要な警告: デフォルト値はたった1回だけ評価される。 これが差になるのは, デフォルトがリストや辞書のような変化可能オブジェクトのときである。 たとえば,下記の関数は次々の呼出しで渡される引数を累積する。
def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3)
これはこう印字される。
[1] [1, 2] [1, 2, 3]
もしも次の呼出しとデフォルトを共有したくないならば, かわりにこのように関数を書けばよい。
def f(a, L=None): if L is None: L = [] L.append(a) return L
関数を "keyword = value" という形式のキーワード引数を 使って呼び出してもよい。たとえば下記の関数
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print "-- This parrot wouldn't", action, print "if you put", voltage, "Volts through it." print "-- Lovely plumage, the", type print "-- It's", state, "!"
は下記のどの方法で呼び出してもよい。
parrot(1000) parrot(action = 'VOOOOOM', voltage = 1000000) parrot('a thousand', state = 'pushing up the daisies') parrot('a million', 'bereft of life', 'jump')
しかし,下記の呼出しはすべて不正である。
parrot() # 必要な引数がない parrot(voltage=5.0, 'dead') # キーワード引数の後に非キーワード引数がある parrot(110, voltage=220) # 引数に対して値が重複している parrot(actor='John Cleese') # 未知のキーワードである
一般に,実引数並びでは,位置引数 (positional argument) は, どのキーワード引数 (keyword argument) よりも前でなければならず, キーワードは仮引数の名前から選ばなければならない。 仮引数にデフォルト値があるかどうかは重要ではない。 どの引数も値を重複して受けとってはならない -- 位置引数に対応する仮引数名を, 同じ呼出しの中でキーワードとして使うことはできない。 ここにある例は,この制約により失敗している。
>>> def function(a): ... pass ... >>> function(0, a=0) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: keyword parameter redefined
最後の仮引数が **name
という形式のとき,それは
仮引数に対応しないキーワードのキーワード引数すべてからなる辞書を受けとる。
これを (次の節で述べる) *name
という形式の仮引数と
組み合わせてもよい。*name
は仮引数並びを超えた位置引数から
なるタプルを受けとる。
(*name
は **name
より前に出現しなくてはならない)。
たとえば,もし次のような関数を定義したならば,
def cheeseshop(kind, *arguments, **keywords): print "-- Do you have any", kind, '?' print "-- I'm sorry, we're all out of", kind for arg in arguments: print arg print '-'*40 keys = keywords.keys() keys.sort() for kw in keys: print kw, ':', keywords[kw]
それはこのように呼び出せる。
cheeseshop('Limburger', "It's very runny, sir.", "It's really very, VERY runny, sir.", client='John Cleese', shopkeeper='Michael Palin', sketch='Cheese Shop Sketch')
そしてもちろんこう印字される。
-- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch
キーワード引数名リストの sort() メソッドは keywords
辞
書の内容印字前に呼びます。
これがされていないと,引数の印字される順序は不確定だ。
最後に,最も使われないオプションとして, 任意個数の引数で呼び出せる関数の指定がある。 これらの引数は1個のタプルにくるまれる。 可変個数引数より前に,零個以上の通常の引数が出現してもよい。
def fprintf(file, format, *args): file.write(format % args)
多くの人の要望により,関数型プログラミング言語と Lisp によく見られるいくつかの 機能が Python に加えられた。 キーワード lambda を使って,名前のない小さな関数を造ることができる。 たとえば "lambda a, b: a+b" は二つの引数の和を返す関数である。 ラムダ形式 (lambda form) は, 関数オブジェクトが求められるところならどこに使ってもよい。 ラムダ形式は構文上,単一の式に制限されている。 ラムダ形式は意味論上,通常の関数定義に対する構文上の糖衣にすぎない。 入れ子にした関数定義と同じく,ラムダ形式は,それを取り囲むスコープからの変数を 参照できる。
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43
ドキュメンテーション文字列の内容と書式について規約ができつつある。
第1行はつねに,対象の目的の,短く簡明なまとめとする。 簡潔さを求め,対象の名前や型をわざわざ述べることはしない。 これらは他の方法で得られるからだ (ただし, 名前がたまたま関数の演算を記述する動詞である場合を除く)。 この行は大文字で始めてピリオドで終える。
ドキュメンテーション文字列が複数行からなるときは, 第2行を空行にして,まとめと,残りの記述を視覚的に分ける。 その次の行から, 対象の呼出し規約や副作用などを記述する1個または複数の段落を書く。
Python のパーサは複数行にわたる Python の文字列リテラルから段付けを はぎとることはしないから,もし望むなら, ドキュメンテーションを処理するツールが段付けをはぎとらなければならない。 これは次の規約に従って行う。 文字列の第1行よりも後の最初の非空行が,ドキュメンテーション文字列全体に 対する段付けの量を決定する (一般に第1行は, 文字列を開始するクォートにとなりあっており, その段付けは文字列リテラルにおいて明らかではないから,使うことはできない)。 それから,この段付けと ``等価な'' 量の空白を, その文字列のすべての行の先頭からはぎとる。 それより少なく段付けされた行は現れてはならないが,もし現れたときは, その先頭の空白をすべてはぎとる。 空白の等価性は,タブを展開した後にテストする (通常は 8 文字 スペース換算とする)。
ここに複数行 docstring の例がある。
>>> def my_function(): ... """Do nothing, but document it. ... ... No, really, it doesn't do anything. ... """ ... pass ... >>> print my_function.__doc__ Do nothing, but document it. No, really, it doesn't do anything.