今しがた紹介した 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 True: ... pass # キーボード入力を待つ(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 True: 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: function() got multiple values for keyword argument 'a'
最後の仮引数が **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.