プログラミング言語 Python

Pythonは 1990 年に Guido van Rossum により発表された、マルチパラダイム (手続き型 + オブジェクト指向 + 関数型)・動的型付 けのプログラミング言語である。ライブラリーが豊富で、Webアプリケーション のほか、機械学習などデータサイエンス分野で広く用いられるため、 2010 年代後半から急速に人気が高まってきている。

Pythonは、最新のバージョン 3.Xの他にバージョン 2.X もいまだに使われてい るが、2.7 が 2.X系列の最後であり、2.7のサポートが 2020年1月1日までとなって いるので、ここではバージョン 3.X について説明する。

ここではC言語と異なる部分を中心に説明する。

Pythonに関係するWebページ

(すべてhttps://を省略している。)
www.python.orgPython Software Foundation
www.python.jppython.jp
www.anaconda.comAnaconda
www.djangoproject.comDjango(Python上のWebフレームワーク)
jupyter.orgJupyter Notebook

Pythonのインストール

インストールについては別ドキュメントで説明する。ブラウザーからPythonを 実行できるWebページもある。

Pythonの実行

対話的な処理系はpythonというコマンドで起動できる。 対話的な処理系では、プロンプト(通常、>>>)のあとに式を入力すれば、 その値を出力する。

>>> 1 + 1
2

quit()またはexit()と入力すれ ば対話的な処理系を終了する。

Pythonを実行する環境として、IDLE(Pythonをインストールしていれば idleというコマンドで起動する), PyCharm, Spyderなどいくつか の統合開発環境 (Integrated Development Environment, IDE) や Jupyter Notebookというアプリケーションもよく使われるが、ここでは説明を割愛する。

代入と関数定義

変数と代入

変数は、次のように記号「=」の左辺に書き、右辺の値を代入する。 (宣言は特になく、初めて使う変数に代入したときに変数が用意される。 このため、綴りの間違いには気を付ける必要がある。)

>>> x = 2  
>>> x * 3
6

関数定義

関数はキーワードdefにより定義することができる。

>>> def fact(n):
...     if n == 0:
...         return 1
...     else:
...         return n * fact(n - 1)
...
>>> fact(10)
3628800      

入力が完了していないと判断するとPython処理系は、上のように第2プロンプ ト「...」を表示して入力の継続を促す。

関数定義は、キーワードdefのあとに関数名(この例では fact)、丸括弧「()」の中の仮引数のコンマ 区切りの並び(この例ではnのみ)、コロン「:」で始まる。 改行後に関数の本体を記述する。

関数の本体はインデント(字下げ)する。つまりdefの位置よりも数 文字(この例では4文字)分下げる。インデントしている限り関数の本体が続い ていると見なされる。

このようにPythonはインデンテーションが文法上意味を持つ言語で ある。(一方、CやJavaはどのようにインデントしてもプログラム の意味は変わらない。)

インポート

通常は、ファイルに関数などの定義を記述して、import文で読み込む。 またPythonのソースファイルには.pyという拡張子を つけるのが通例である。

ファイル factorial.py

>>> from factorial import *
>>> fact(20)
2432902008176640000   

Ideoneで実行 Rextesterで実行 JDoodleで実行

この fromimport * という形式の import文は、〜というモジュール(ファイル名から拡張子 .pyを除いたもの)から変数や関数などの定義を読み込むことを意 味する。

リテラル

数値リテラル

整数や浮動小数点数のリテラルは他の言語と大きな違いはない。また、接尾辞 jを整数や浮動小数点数リテラルにつけることで虚数を表 すことができる。

>>> (1 + 1j) / (1 - 2j) 
(-0.2+0.6j)

文字列リテラル

文字列リテラルは、二重引用符「"」または一重引用符「'」 で囲まれた文字列である。文字リテラルは存在しないので一重引用符/二重引 用符どちらを使っても意味は変わらない。

>>> "hello"
'hello'
>>> 'world'
'world'

また三連続の二重引用符「"""」または一重引用符 「'''」で囲むと改行や一重引用符・二重引用符を含む 文字列を表すことができる。

>>> """Mike said "Hello!"
... and Anne said "Good Bye!"
... """
'Mike said "Hello!"\nand Anne said "Good Bye!"\n'

引用符の前に接頭辞fまたはFをつけると、 波括弧「{」〜「}」に囲まれた部分が式として評価さ れ、文字列中に埋め込まれる。

>>> x = 13
>>> f"The factorial of {x} is {fact(x)}."
'The factorial of 13 is 6227020800.'

問: では、f文字列のなかに波括弧(「{」または「}」)を 含めたいときはどうすれば良いか調べよ。

演算子と組み込み関数

算術演算子

演算子は C や Java の演算子と似ているが、「/」は整数同士の演算 でも通常の(小数になる可能性のある)除算である。整数としての除算の商を求めるには 「//」を用いる。余りを求める演算子は「%」 である。

>>> 1 / 3 
0.3333333333333333
>>> 17 // 6
2
>>> 17 % 6
5

**」は累乗を求める演算子である。

>>> 2 ** 10
1024
>>> 2 ** 0.5
1.4142135623730951

print関数とinput関数

画面に出力するにはprint関数を用いる。いくつかの引数をコンマで区切って 与えるとそれらを順に出力する。

>>> y = 23
>>> print(x, "+", y, "=", x + y)
13 + 23 = 36

最後に、sep=〜と指定すると、区切り文字を〜に変えることができる。 このように「キーワード=式」のカタチで与える引数をキーワード引数 という。 (区切り文字を何も指定しないと上の例のように空白文字が区切りに使われる。)

>>> print(x, "+", y, "=", x + y, sep=',')
13,+,23,=,36

一方、input関数はキーボードから文字列を読みこむ関数である。 int関数(整数への変換) やfloat関数(浮動小数点数への変換)と組み合わせる ことで、文字列をそれぞれ整数や浮動小数点数に変換することができる。

ファイル名 temp.py

Ideoneで実行 Rextesterで実行 JDoodleで実行

制御構造

if文

条件分岐を表すif文はifというキーワードのあと、条件式、コロン 「:」で始まり、改行後に条件が成り立つときに実行する文を並べて 書く。

条件が成り立つ時に実行する文はインデント(字下げ)する。つまり ifの位置よりも数文字(この例では4文字)分開始を下げる。 ここに複数の文を並べることもできる。同じ字下げ幅である限りは、 条件が成り立つ時には実行する。

条件が成り立たない時に実行する文は キーワードelse、 コロン「:」のあとに改行して書く。

また、ifelse の間に elifとい うキーワード、条件式、コロン「:」で始まり、改行後にインデント した文の並び、というかたちをはさむことができる。この場合、上から順に条 件式を評価し、成り立つときに対応する文の並びを実行する。

論理演算子

条件式は and(〜かつ〜)、or (〜または〜)、not(〜でない)などの論理演算子で組み合わせる ことができる。

Python では(CやJavaと異なり)比較演算子は連ねることができるので、この 例は次のように書くこともできる。

コメント

上の例で使われているように、「#」から行末まではコ メントである。

for文

決まった回数の繰り返しを実現するときにはfor文が使われる。次のように キーワード for、変数、キーワード in、式、コロン「:」 という形式で使われる。

ファイル名 temp2.py

Ideoneで実行 Rextesterで実行 JDoodleで実行

ここでrange関数は、range(n)が、0 から n - 1 までの整 数の列を返すような関数である。

これを実行すると、変数iに 0, 1, …, 4が順に代入され、次 のように出力される。

Hello
   0 回目
Hello
   1 回目
Hello
   2 回目
Hello
   3 回目
Hello
   4 回目

他にrange関数は次のようなカタチでも使われる。

range(n)\(0\), \(1\), …, \(n - 1\) を返す。
range(m, n)\(m\)\(m + 1\), …, \(n - 1\) を返す。
range(m, n, s)\(m\)\(m + s\), …, \(m + k \cdot s\) を返す。

ただし、\(k\)\(m + k \cdot s\)\(n\) 未満となるような最大の \(k\) である。

while文

繰り返しを表すwhile文はwhileというキーワードのあと、条件式、コロン 「:」で始まり、改行後に繰り返す文をインデントして並べて書く。

Ideoneで実行 Rextesterで実行 JDoodleで実行

ここでprint関数に、end=〜とキーワード引数を指定すると最後に出力 する文字を変えることができる。(何も指定しないと改行文字が最後に出力さ れる。)

これを実行すると、次のように出力される。

1000, 500, 250, 125, 62, 31, 15, 7, 3, 1, 

なお、Python に do〜while 文に相当する構文はない。

リスト

リストは単純だが有用性の高いデータ型で、関数型言語など で多用されるデータ型である。配列と同様に(同種の)データを集めたものだが、 要素の追加・削除が可能である。

リストリテラル

リストを構成するためには、角括弧[])で 囲み、各要素をコンマ「,」で区切って並べる。例えば、 []は空リストを表し、[2, 3, 5] は3つの要素からなるリス トを表す。

リスト内包表記

リスト内包表記 (list comprehension) は数学で使われる集合の表記に似た糖 衣構文 (syntax sugar) である。

>>> [x * y for x in range(1, 5) for y in range(5, 8)]
[5, 6, 7, 10, 12, 14, 15, 18, 21, 20, 24, 28]
>>> [x * x for x in range(1,11) if x % 2 == 1]
[1, 9, 25, 49, 81]

リスト内包表記は、角括弧([])のなかに最初に式を一 つ書き、そのあとに、「for 変数 in 式」というカタチか 「if 式」というカタチを並べたものである。(ただし並びの最初は 「for 〜」のカタチでなければいけない。)その値は 「for 変数 in 式」というカタチで与えられた繰り返し の中で「if 式」というカタチで与えられた条件が成り立つときの 最初の式の値を順に並べたものになる。

問: 次のリスト内包表記の値は何か?

  1. [x * y for x in [1,2] for y in [3,5,7]]
  2. [(x, y) for x in [1,4,7] for y in [2,5,8] if x < y]

タプル

タプル(tuple, 組)は要素を「,」(コンマ) で区切って並べ、丸括弧「(」と「)」で囲んで表す。(文 脈によっては丸括弧を省略できる場合がある。)リストは通常、各要素は同 種のものからなるが、タプルは要素の種類が同一である必要はない。

タプルは以下の例のように関数の戻り値に使うこともできるし、代入文の左辺に 書くこともできる。

ファイル名 temp3.py

Ideoneで実行 Rextesterで実行 JDoodleで実行

特に次のように書くと左辺の 2 つの変数への代入が同時に行われるので、2 つ の変数の内容を入れ替えることができる。

y, x = x, y

(この例ではタプルのまわりの丸括弧が省略されている。)

問: 3つの実数 a, b, c を受け取り、二次方程式 \(a x^2 + b x + c = 0\) の 2 つ の解を組として返す関数 quadratic を定義せよ。

標準ライブラリー関数のzipは 2つ以上のイテラブルの 同じ位置の要素をタプルにしたもののイテラブルを返す関数である。イテラブ ルの長さが異なる場合は、短い方にあわせる。

>>> list(zip([1,3,5,7,11], [2,4,6,10]))
[(1, 2), (3, 4), (5, 6), (7, 10)]

高階関数とラムダ式

高階関数関数を引数に取る(あるいは 戻り値とする) 関数である。

リストに対しては、いくつかの高階関数が標準ライブラリーに用意されている。 例えば、mapは、リストの要素に一斉に関数を適用し、 その戻り値のリストを返す関数である。(正確にはイテラブル (iterable) を 受け取って、イテラブルを返す関数である。リストもイテラブルの一種だが、 一般にイテラブルを表示するためにはlist関数でリストに変換する必要が ある。)

このメソッドは次のように使用することができる。

>>> list(map(chr, [97, 98, 99, 100]))
['a', 'b', 'c', 'd']
>>> def twice(n):
...     return 2 * n
>>> list(map(twice, [97, 98, 99]))
[194, 196, 198]

ここで、chr は文字コードに対し対応する一文字からなる文字列を返す関数である。

ところで高階関数の引数として使うtwiceのような小さな関数にいち いち名前をつけるのは面倒なので、名前をつけずに関数を表現する記法が用意 されている。これをラムダ式という。 (この名前は、かつて数学の一分野で、この目的のためにギリシャ文字の 「λ」が使われたことに由来する。)

例えば、lambda x: 2 * xという式でtwiceと同等の関数を表 す。キーワードlambdaとコロン「:」の間に仮引数のコンマ区切りの並びを、 コロンの右側に戻り値の式を書く。次はラムダ式の使用例である。

>>> list(map(lambda x: x * x, [2, 3, 5]))
[4, 9, 25]

また、filterは、リストの要素の中で、与えられた関数 の値を真にする要素だけのリストを返すメソッドである。

>>> list(filter(lambda x: x % 2 ==  0, [2, 3, 5, 8]))
[2, 8]

ジェネレーター

Python のジェネレーター関数 (generator function) はコルーチンの 一種 (stackless coroutine) を提供する。コルーチンとは、2つ以上のプログ ラムの実行単位が、 交互に制御を受け渡しながら実行されていく方式のことである。通 常の関数(サブルーチン)はリターンする(戻り値を返す)と、次に実行する 時はもう一度最初からになるが、コルーチンは次に実行する時に前回リターン した地点の続きから実行する。

ファイル名 fib.py

Pythonのジェネレーター関数ではyieldというキーワード を使って値を生成する。

ジェネレーター関数を呼び出すと、すぐに関数内部のコードが実行されるので はなく、一旦、ジェネレーターイテレーター (generator iterator) が作られ て返される。このジェネレーターイテレーターを引数とし てnext関数を呼び出すと、ジェネレーター関数内部のコー ドが実行され、yieldされた値を返す。さらにnext関数を呼 び出すと yield 文のつづきから実行が再開され、やはり、 次の yield された値を返す。

gen = gfib(100)
print(next(gen))        # 1 を出力する
print(next(gen))        # 1 を出力する
print(next(gen))        # 2 を出力する
print(next(gen))        # 3 を出力する
print(next(gen))        # 5 を出力する
print(next(gen))        # 8 を出力する

ジェネレーターイテレーターは for文のinの次の式でも使う ことができる。

for文 はジェネレーターイテレーターを受け取ったnext関 数によって返される値を順に変数に代入してループする。ジェネレーター関数 の中のコードの実行がreturn文によりリターンするか、関数を抜けるとループ を終了する。

Ideoneで実行 Rextesterで実行 JDoodleで実行

この部分は「1 1 2 3 5 8 13 」と出力する。

ジェネレーターは必ずしも有限個の要素で終わる必要はない。 次の例は無限に yield する例である。

次のようにすると、

Ideoneで実行 Rextesterで実行 JDoodleで実行

この部分は「1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 」と出力する。

問: 整数 \(n\) を引数として受け取り、最初は \(n\) を yield し、以降は、

  1. 直前に yield した値が偶数ならば \(n / 2\) を yield する、
  2. 直前に yield した値が奇数ならば \(3 n + 1\) を yield する、

という処理を繰り返すジェネレーター関数 hailstoneを定義せよ。

例: エラトステネスの篩(ふるい)

最後に、素数列を生成するプログラムを例として挙げる。 (ただし、この定義は効率面での改良の余地は大いにあると思われる。)

この primes() は無限に素数を生成するので、例えば range のように有限のものと zip する。

Ideoneで実行 Rextesterで実行 JDoodleで実行

このfor文は、

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 

と20個の素数を出力する。


Koji Kagawa (kagawa@eng.〜)
(〜の部分は SPAM mail 予防のため省略します。)