ここではPythonというプログラミング言語について学びます

注意: 元はWindows上のPython2用でしたが、 これはPython3用に書き変えたものです。

Pythonの基本

Pythonは変数の型の宣言を必要としない、オブジェクト指向言語の一つで、 インタプリタ(つまりコンパイルを必要としない)で動くプログラミング言語です。

Pythonのプログラムを実行するにはいくつかの方法があります。

[コマンドプロンプトを開く]
コマンドプロンプトを開くのは、あるフォルダにあるプログラムファイル(例えば test.py)を実行したいからです。そのためにはcdコマンドを使って、ワーキングディレクトリ(作業用フォルダ)をそのフォルダにしないといけません。

そこで、対象とするファイルがあるフォルダで「コマンドプロンプトを開く」と、cdコマンドを使ったりしなくても、コマンドプロンプトを開いた時点で、ワーキングディレクトリがそのフォルダにセットされる、ということができます。 そのためのやり方は、ファイルがあるフォルダを開いておき、シフトキーを押したままマウスの右ボタンをクリック、表示されたメニューから「コマンドプロンプトをここで開く」を選択することです。


私の勧めは最後の方法です。エディタに作ったプログラムが残ることと、 pythonを使うと、一つ一つのコマンドの実行結果がどのようなものか、すぐにわかるからです。 ちゃんと一つ一つのコマンドが動くことが確かめられたら、 エディタにはちゃんと動くプログラムが残っているので、 そのファイルに名前をつけて、一番目か二番目の方法で実行する、というのがよいでしょう。

もっともIDLEやspyderが使える環境にあれば、それを使ってみるのも良いでしょう。

最初のPythonプログラム

「こんにちは」を画面に表示するプログラムを書いてみましょう。 まずはTera Padや秀丸エディタのようなエディタを用いて
print ("hello, world!")
と打ち込んでみてください(この資料からコピーしてエディタにペーストするのでも構いません)。
[命令の最後に;をつけなくても良い?]
プログラミング言語Cなどでは、命令文の最後にセミコロン ; をつけなければなりません。 しかし、Pythonでは不要です。もっともセミコロンが機能しないわけではありません。 一行にいくつかの命令を書きたい場合には、命令の区切りとしてセミコロンが使えます。

そして、first.pyという名前をつけて『ファイルに保存』してください。 これがデスクトップに保存されたとすれば、前に述べたやり方で デスクトップから「コマンドプロンプトを開き」、次のようにPythonプログラムを使って実行させます:
python first.py
このように実行すれば、次のように表示されるはずです。
hello, world!

printというのがPythonの関数の一つで、画面に引数の値を表示する、というものです。そして、"hello, world!" の部分がその引数です。Pythonは、数だけではなく、このような「文字列」を扱うことが簡単にできます。ここで文字列とは、 " "、つまり引用符号(ダブルクォート、もしくは二重引用符と言います。)で囲まれている文字の並びのことです。

今度はpythonを使ってみましょう。この場合、ワーキングディレクトリがどのようにセットされていても構いません。
python
すると、メッセージが5行近く表示されたあと、次の表示がでるでしょう:
>>> 
この>>> はプロンプト(prompt, 入力促進)といい、コンピュータがあなたの入力を待っていることを表しています。 そこで、次のように入力し、最後にEnterキーを入力してください。
print ("こんにちは")
すると、次のような表示がえられるでしょう。
こんにちは
>>> 
ここで「こんにちは」の部分がprint関数による表示です...え、文字化けして、「こんにちは」とは出ませんでした?

日本語の扱いはどんなプログラミング言語でも少しやっかいです。しかし、 unicodeが今や事実上の標準コーディングになった今、少し扱いやすくなりました (とは言っても、今見たように文字化けすることがありますから注意しましょう)。 文字化けした場合は、次のように入力して最後にEnterキーを押してください。

print (u"こんにちは")
今度は文字化けせずに表示されたことでしょう。ここで付け加えられたuは、ユニコード(UTF-8)に変換させるためのものです。

[プログラムファイルにおけるコーディングの問題]

test.pyの内容を次のように変えて、python test.pyを実行したとしましょう。
print (u"こんにちは")
pythonを呼び出して実行したときには、ちゃんと表示されたものです。 しかし、この場合はうまくいきません。それには2つの追加作業が必要になります。
  1. プログラムの1行目に次を書き込んでください。これは文字コードとしてユニコードを使っているという宣言になります。
    # -*- coding: utf-8 -*-
    
  2. 文字コードをUTF-8にする。デフォルトではShift-JISというコーディングになっています。TeraPadと秀丸エディタとではコーディングの変換の仕方が異なりますので、それぞれのエディタの方法で変換してからセーブしてください。

さて、pythonを起動したあと、次は以下を試してみてください。

a=u"こんにちは"
print (a)
ここでは、文字列「こんにちは」を変数aに代入し、printを使ってaの値を表示させてみました(print文はデフォルトとして改行します)。ここでプログラミング言語Cを学んできた人は大事なことに気づくことでしょう。それは、変数aをいきなり(変数の宣言をすることなく)使っていることです。
[変数の規則]
Pythonの変数は半角文字のアルファベットか数字か _ (下線、アンダースコア)という記号から作られていなければなりません。 また先頭は数字であってはいけません。大文字と小文字は厳密に区別されます。 なお以下に示す単語は予約語といって、変数名に使えません。
and del from not while as elif global or with
assert else if pass yield break except import print
class exec in raise continue finally is return
def for lambda try

このようにPythonの特徴の一つは、変数は(定数も)宣言なしに使え、しかもどんな型のオブジェクトも代入できる、ということです。たとえば、続けて次のようにしても怒られません。 (以下の例は、さっきは文字列を値とした変数aに、今度は数を代入しようとするものです)

a = 12345679 * 9
print (a*8 )

ここで起動したpythonを終了させる言葉を書きます。それはquit()です(exit()でも同じことができます)。


文字列と数

これまでは、プログラムの中で、文字列という種類の対象だけを扱ってきましたが、 ここでは、プログラムで数も扱うことにしましょう。 数に対しても、文字列について今まで学んできたことがあてはまります。 つまり、変数への数の代入や変数からの数の取り出しなども全く同じような操作でできます。 ただし、数は文字列と違って、プログラムの中ではそのまま書けば意味を持ちます。 (注意: 引用符で囲むと、数ではなく文字列として扱われます。)

num = 1000
print (num, u"\n")
[\nの説明]
\ という記号は、引用符で囲まれた文字列の中で、nやtのような記号と組み合わされると特別な意味を持ちます。 ここで用いられた\nは「改行コード」を表します。これをprint<(/T>すると、何も表示されずに改行が発生します。また、\tは「タブ」を表します。その効果は実際に次のようなプログラムを実行してためしてみてください(このように\tの位置によって表示されるスペースの個数が変わることに注意)。
print(u"ここにはタブがありません")
print(u"ここに\tタブが2つ\tあります")

式と値

これまで、変数を単独で扱ってきましたが、変数や文字列、数を要素にして、 式を作ることができます。
例えば、次のプログラムの中の num1 + num2 は式の例です。

num1 = 1000
num2 = 2000
wa = num1 + num2
print ( wa)

このように、プログラムの構成要素として「式」があります。 簡単な式を組み合わせてより複雑な式が構成できるというのは、一般の数式の場合と同じです。

[#, コメント]
Pythonでは文字列の中でなければ、#以降はコメントとみなされます。 つまり#から書かれているのは「人間のためのメモ」であって、Pythonとしての処理は行われません(言い換えれば、読み飛ばしされます)。
ただ # がコメントという機能をもつのは、行末までです。もっと長くコメントを書きたい人は、調べてみてください。
num1 = 1000
num2 = 2000
kekka = (num1 + num2) * num2    # * は掛算を表す記号です。
print ( kekka)

式は変数と同様に「式全体」で値を持ちます。 値を持つプログラムの構成要素を式だと言ってもよいでしょう。
文字列を対象にした式も作れます。
たとえば次のように、文字列を + で結合したものも式です。この式を実行すると、それらが結合 された文字列が式の値になります。

kotoba = "Hello, " + "Mr. Taro!"
print ( kotoba)

もう少し詳しく、プログラムの実行過程を見ていきましょう。 上のプログラムを実行すると、まず1行目の命令が実行されるのは当然ですね。 このような実行されるプログラムの構成単位をと呼びます。 命令が言葉の集まりとして構成されているからです。 一行目は、変数への代入を行う命令ですから、「代入文」と呼ぶこともあります。 代入文は、等号(=)の右辺の式を実行し、その結果の値を等号の左辺にかかれた変数に代入するものです。 さて、この代入文は今までに出てきた単純な代入文とは違って、右辺が式になっています。

kotoba = "Hello, " + "Mr. Taro!"
右辺は
"Hello, " + "Mr. Taro!"

となっていて、文字列が「 + 」の記号で繋がっている式です。 このように文字列を演算の対象とする「 + 」は二つの文字列をつなげるという働きをします。 この式を実行すると、二つの文字列が繋がって一つの文字列、

"Hello, Mr. Taro!" 

が出来上がり、これが式の値になります。 そして「 = 」を使う代入文は右辺の式の値を左辺の変数に代入するということになりますから、 文字列"Hello, Mr. Taro!" がkotobaという変数に代入され、この変数の値になります。


キーボード入力

次のプログラムでは、キーボードからの入力を受け取るための命令文が使われています。 input() がその命令文です。 この命令文が実行されるとキーボードからの入力を待つ状態になります。 文字が入力されるとプログラムの実行を再開し、受け取った文字列をプログラムの 中で扱うことができるようになります。 次のプログラムでは、入力された文字列を aisatsu という変数に代入しています。
まずはこのプログラムをコピーし、utf-8に文字コードを変換したaisatsu.pyというファイルを作り、 python aisatsu.py を実行して、キーボードからの入力を受け取れていることを確認してみましょう。 ここで、「あいさつ:」と表示された後に「こんにちは」などの文字列を入力して、Enterキー を押してください。 ちなみに、コマンドプロンプトで日本語を使うときは (Altキー を押しながら )半角/全角キーを押します。また半角文字モードに戻すのも、(Altキー を押しながら )半角/全角キーを押します。

# -*- coding: utf-8 -*-
# pythonに utf-8を使っていることを知らせる---日本語の扱いには必要

print (u"あいさつ:", end="")     # end=""によって改行されない
aisatsu = input()

print ("\n")
print (aisatsu, u"。お元気ですか?")
注意: print文はデフォルトでは改行が起こるが、今の例のようにend=を指定すれば、改行が起こりません。
[今の例をIPythonやPythonで逐次実行する人のために]
IPythonやPythonで今の例を逐次実行すると、「あいさつ:」の後に改行が入ってしまうので、 どこで入力したらよいか少しわかりにくくなります。 そこで、ここでは次のようにしてください。1行目のprint文とaisatsuへの代入文の間にあるセミコロン(;)がキーです:
print (u"あいさつ:",end="") ; aisatsu = input()

print (aisatsu, u"。お元気ですか?")

[print文で半角の空白が入ることに気づいた人に]
今の課題の結果で分かるように、複数の引数をprintする場合、間に空白が入ります:
こんにちは 。お元気ですか?                   # 先の課題で「こんにちは」を入力した場合
これを防ぐには二通りの方法があります。
  1. 空白が一つはいるのだから、強制的に出力を一つ戻させる。そのために \b という制御文字(\nや\tの仲間)が使えます。つまり以下のようにします:
    print (aisatsu, u"\b。お元気ですか?")
    
  2. 文字列をつなげたものを出力させる。この場合は次のようにすればできるはずです:
    print (aisatsu + u"。お元気ですか?")
    
    つまりaisatsuという文字列とu"。お元気ですか?"をつなげた文字列を出力するのです。しかし、実際にはこれはうまくいきません(実際に試してみてください)。そこで、次のように、aisatsu変数の値をunicode関数を使って変換する必要があります(注意:入力文字列がshift-jisであると仮定しています):
    print (unicode(aisatsu,"shift-jis") + u"。お元気ですか?")
    

参考:inputは引数を取れ、この引数はプロンプトとして表示される。 だから今の例は以下のようにもかける:

aisatsu = input("あいさつ: ")
print (aisatsu + "お元気ですか?")

課題1

課題1-1

「キーボード入力」で示したプログラムを参考として、 以下のような実行結果になるプログラムを作成しなさい。 ただしここで、オレンジ色の文字はキーボードからの入力を表しています。

名前:中京太郎
あいさつ:こんにちは

中京太郎さん、こんにちは。
お元気ですか?

課題1-2

次のように、キーボードから会計金額と人数を入力すると、一人当たりの割り勘金額を 計算してくれるプログラムを作成しなさい。(オレンジ色の文字はキーボードからの入力を 表しています。キーボードから数の入力を受け取る方法は、下の解説を参照してください。)

お会計:10000
人数:3

お一人様3333円です。
不足金額は1円です。

[キーボードから数の入力を受け取る]

キーボードから数の入力を受け取るときは次の命令文を使用します。 これにより、キーボードから入力された数字(注意:これは「文字」の並び)を、 プログラムの中で整数(注意:これは「数値」)として扱うことができるようになります。

kaikei = int(input())
このようにint関数は文字列を整数に変換します。また、float関数は、文字列を浮動小数点数に変換します。

注意: 実行時には半角数字で整数を入力してください。

[割算]

割算を計算するときは / を使用します。

print (10000 / 3)
3333.3333333333335

数が変数に代入されている場合も、同じように計算することができます。

kaikei = 10000

print (kaikei / 3)
3333.3333333333335

ここで、なぜ 3333 にならないのか、と思った人がいるかもしれません。 これについては後で述べますが、Pythonでも「整数」と「小数点数をふくむ数(これを 浮動小数点数と呼びます)」が区別されていますが、 デフォルトは浮動小数点数だからです。 整数としての値を求めたければ、

print (kaikei // 3)
というように、/ ではなく // を使って割り算します。
[余りを求める計算]

割算の余りを求める計算をするときには(Cプログラミング言語と同様に) % を使用します。

print (10000 % 3)
1

課題1-3

次のプログラムを実行すると何がどのように表示されるのか予測して、答えなさい。 その後、実際に実行して、予測と合ったかどうかも報告しなさい。


num = 10

num = num + 10
print (num)

num = num * 10
print (num)

num = num - 150
print (num)

num = num // 20
print (num)

num = num ** 2
print (num)
[掛算と乗数]

掛算を計算するときは(Cプログラミング言語と同様に) * を使用します。

print (1000 * 3)
3000

数が変数に代入されている場合も、同じように計算することができます。

num = 1000

print (num * 3)
3000

**は乗数を表します。

print (2 ** 10)
1024

課題1-4

次の実行結果のように、長方形の面積を計算するプログラムを作成しなさい。 (オレンジ色の文字はキーボードからの入力を表しています。)

長方形の面積を計算します。
縦と横の辺の長さを入力してください。
縦:10
横:20
長方形の面積は 200 です。

縦と横の辺の長さは、キーボードからの入力を受け取るようにします。 キーボードから数の入力を受け取る方法については、 前述のキーボードから数の入力を受け取るにはを参照してください。

ここでは数を2つ受け取る必要がありますので、キーボードから数の入力を受け取るための命令文を、2つ書く必要があります。 2つの数を受け取ったら、それらを使って長方形の面積を計算し、結果を表示しなさい。 掛算の計算には * を使用します。

課題1-5

次のプログラムを実行すると、ディスプレイに何が表示されるか、予測しなさい。 次に、実際にプログラムを実行してみて、自分の予測と適合したかどうかを報告しなさい。 自分の予測と合わなかった場合は、どうして合わなかったのか理由を考え、それを報告しなさい。
ただし、まず、次のintの解説を読んで、理解してから、取り掛かること。

print ("年齢を整数でキーボードから入力してください。")
nenrei = int(input())                       #ここで、20を入力することにする。
print ("あなたの年齢は", nenrei, u"才です。")

[解説:intの役割]

mojiretsu = "20"
kazu = 20
print (mojiretsu == kazu)
ここで==は左辺と右辺の値が等しい(同値)場合にTrue、そうでない場合はFalseを返す論理演算子です。このプログラムを実行すると、Falseが表示されます。
ちょっと紛らわしいことのように思うかもしれませんが、これから分かることは"20"と20が違うものだ、ということです。 "20"は文字"2"と文字"0"が結合したもの(文字列)ですが、 20はです。この違いは大事です。 ですから、次のような足算はできません。つまり、文字列と数を足し合わせることはできません。
mojiretsu = "20"
kazu = 20
goukei = mojiretsu + kazu
print (goukei)
つぎのように、文字列をまず数に直してからなら、足し算ができます。
mojiretsu = "20"
kazu = 20
goukei = int(mojiretsu) + kazu
print (goukei)
このように、intは「数」を表す文字列を数に変換する役割を持っています。

変数の値の更新

プログラミング言語Cでは変数の値にある数を足したり掛けたりするのに+=*= という代入方法が使えました。これはPythonでも同様です。例で示すことにします。
>>>  a = 10
>>>  a += 5
>>>  print ('a = ', a)
a = 15
>>>  a *= 10
>>>  print ('a = ', a)
a = 150
>>>  a /= 5
>>>  print ('a = ', a)
a = 30
>>>  a %= 8
>>>  print ('a = ', a)
a = 6
>>>  a **= 2
>>>  print ('a = ', a)
a = 36

型と型変換

どのプログラミング言語でも数と文字列(string)は処理対象となる基本的な「型」です。文字列とはその名前の通り文字の並びのことで、前後に引用符(' もしくは " ) でくくります。ここで文字列を'(一重引用符という)でくくり始めた場合は、終わ りも同じ'でなければなりません。これは”(二重引用符)の場合も同じです。

数には整数と実数とがあります。整数はintと表記され、実数は「浮動小数点数」と呼ばれ、floatと表記されます(プログラミング言語Cと同じ表記です)。変数の値がどの型のものかを調べるにはtypeという関数があります。

課題1-6

以下を実行し、どのような応答があったかを答えよ。
x = 'Hello, World!'
type(x)
x = 3
type(x)
x = 3.14159265
type(x)
この課題から分かるように、typeはその型を返す関数です。

Pythonには、値を本来の型から別の型にする関数が用意されています。前に述べたint 関数は、任意の値をとり、整数に変換します。ただし、整数に変換できない場合にはエラーとなります。

>>> int('32')
32
>>> int('hello')
ValueError: invalid literal for int() with base 10: 'hello'
>>> int(3.14)
3
>>> int(-2.3)
-2
floatは、整数や文字列を浮動小数点数に変換します:
>>> float(32)
32.0
>>> float('3.14159')
3.14159
str は、引数を文字列に変換します:
>>> str(32)
'32'
>>> str(3.14159)
'3.14159'

条件分岐

条件分岐とは、次のように状況を判断して、適切な反応ができるようなプログラムの仕組みです。 次のコンピュータとの対話例を見てください。

コンピュータ:あなたの年齢はいくつですか?(年齢を数字で入力してください。)
年齢:19
コンピュータ:残念ですが、まだ、お酒を飲んではいけない年齢ですね。

年齢に20を入力すると、

コンピュータ:あなたの年齢はいくつですか?(年齢を数字で入力してください。)
年齢:20
コンピュータ:おめでとう。もう、お酒を飲める年齢ですね。

このように、入力によって違う応答を返すことができます。

このようなやりとりを実現するためには、入力された年齢(これは数として扱います)によって、 コンピュータに異なる振る舞いをさせるプログラムを作成する必要があります。 そのためには次のような、ifの構文を使った、条件分岐の仕組みが必要です。注意:if文とelse文の後にはコロン(:)が必要です。またそれぞれの文の前にはきっちり同じだけのスペースを置く(インデントする)ことにも気をつけましょう。
[コロンとインデントの意味]

今の例をプログラミング言語Cで書くとすれば、次のように書けます:
#include <stdio.h>
int main(void) {
  int nenrei;
  printf("コンピュータ:あなたの年齢はいくつですか?(年齢を数字で入力してください。)\n");
  printf("年齢:");
  scanf("%d", &nenrei);
  if (nenrei < 20) {		// if文の始まり
	printf("コンピュータ:残念ですが、まだ、お酒を飲んではいけない年齢ですね。\n");
  } else {			// if文の終わりとelse文の始まり
	printf("コンピュータ:おめでとう。もう、お酒を飲める年齢ですね。\n");
  }				// else文の終わり
  return(0);
}
この例においても、インデント(段付け)によって、プログラムの構造が暗黙的に示されていました。 ここでプログラムの構造とは、どのような命令文からプログラムが作られているか、ということです。 このプログラムのmain関数においては、変数宣言(int nenrei)、printf文が2つ、scanfによる入力、 そしてif文とelse文、最後にreturn文によって構成されています。これらがみなmain関数を構成します。またこれらの文の前にはスペース2個が置かれています。これらとif文の中のスペース8個が前にあるprintf文と比べてみてください。スペース8個が置かれたprintf文はそれによりはっきり「main関数を直接構成するものではない」ことが示されています。このようにすれば人間にはプログラムの構造がとても見やすくなります。とはいっても、プログラミング言語Cでは、このようなスペースを書かなくても(もっといえば改行しなくても)、プログラムとしてコンパイル/ビルドできますし、正常に答えを返します。
それに対し、Pythonはインデントとコロンによって、プログラムの構造を明示しないとエラーになるプログラミング言語です。これから見るように、条件分岐や繰り返し、関数などを構成する文は(コメントですら)、その「親」にあたる文や関数定義の前に置かれた個数のスペースに加えてきっちり同じ個数のスペースが前に置かれていないといけません。またコロン(:)は、この後ろにその文を構成するプログラム文が続くという印です。ですから、これから見るように、if文やelse文、for文やwhile文などの繰り返し、関数の定義を行うdef文などの最後にはコロンがないとエラーになります。

if (条件判定式):
  
  
  ...
else:
  
  
  ...
まずは実際に条件分岐の仕組みを持つプログラムを動かしてみて、上の対話例と同じような振る舞いをするか確認しておきましょう。
次のプログラムをコピーしてファイルに保存し、実行して振る舞いを確かめなさい。 どのような年齢を入力するとどんな応答が返ってくるか確かめて、わかったことを報告しなさい。 いろいろな年齢を入力して試してみるとよい。

print (u"コンピュータ:あなたの年齢はいくつですか?(年齢を数字で入力してください。)")
print (u"年齢:",)
nenrei = int(input())

if (nenrei < 20):
  print (u"コンピュータ:残念ですが、まだ、お酒を飲んではいけない年齢ですね。")
else:
  print (u"コンピュータ:おめでとう。もう、お酒を飲める年齢ですね。")

条件分岐は強力な仕組みです。 コンピューターが人間のための強力な道具になるのは、 このように場面に応じて適切に動作するようにプログラムできるからである、 と言っても言い過ぎではないでしょう。 知的な振る舞い、つまり適切な場面で適切な動作をさせる根源にこの「条件分岐」があるのです。
ifで作られる条件分岐のプログラムの、基本の形は次のようなものです。

if (条件判定式):
  #上の括弧の中の条件判定式の実行結果が真のときだけ以下の文が次々に実行される。
   
  
  ...
else:
  #上の括弧の中の条件判定式の実行結果が真でないときだけ以下の文が次々に実行される。
  
  
  ...
先にあげたプログラムがどのように動作するのか、年齢に19という数を入力した場合を例に、ていねいに追いかけてみましょう。
print (u"コンピュータ:あなたの年齢はいくつですか?(年齢を数字で入力してください。)")
print (u"年齢:")
nenrei = int(input())         #キーボードから19という数が入力されると...

if (nenrei < 20):
  print (u"コンピュータ:残念ですが、まだ、お酒を飲んではいけない年齢ですね。")
else:
  print (u"コンピュータ:おめでとう。もう、お酒を飲める年齢ですね。")

ifの括弧の中の条件判定式が問題です。 この括弧の中の「条件」が判定され、合っていればすぐ下の部分が実行されます。 条件に合っていない場合は、elseの下に書かれた部分が実行されます。

条件判定式について詳しく見てみましょう。 条件判定式の部分が、実際に実行されることに注意してください。 実行されると値を持つのが式でした。 条件判定式も式ですので、実行されるとその値が求められます。 上の条件判定式の場合、nenrei < 20 という式がまず実行され、「19は20より小さい」という意味に合致しますので、Trueという値がこの式の値になります。 Trueというのは、条件判定式が正しいことを表す値です。 反対に、条件判定式が間違っている場合はFalseという値で表されます。

式の値として、これまでは文字列だけを扱ってきましたが、 これからは真を表すTrue偽を表すFalseも扱うことになります。これらは「真偽値」と呼ばれます。文字列と数とは違う「第3の」種類の値です。 今度はこの部分だけを、詳しく見てみましょう。

課題2

課題2-1

条件判定式が実際に値を持つことを確かめてみましょう。
次のプログラムを実行すると何が表示されるか考え、予想を書きなさい。
次に、実際にプログラムを実行してみて、自分の予想と適合したかどうかを報告しなさい。
予想と違う結果になった場合は、自分の予想がどう間違っていたか説明し、どのように考えてそのような結果になったのか説明しなさい。

nenrei = 19
print (nenrei < 20)

print ("\n")

nenrei = 21
print (nenrei < 20)

[ヒント1]

ここまでで扱った3種類の値(文字列、数、真偽値)を、printを使って表示してみましょう。

print (u"こんにちは"    #文字列)
print (100             #数)
print (True            #True)
print (False         #False)

真偽値のTrueとFalseは数と同じように、そのままTrue、Falseと表示されます。

こんにちは
100
True
False

[ヒント2]

次のような文字列の連結や、数の計算も「式」の一種です。

#文字列の連結
print ("Hello, u" + "Mr. " + "Taro Chukyo")

#数の計算
print (100 * 2)

式は実行されると値を持ちますので、printによって表示されるときにはその値が表示されます。

Hello, Mr. Taro Chukyo
200

条件判定式も「式」ですので、何らかの値を持ちます。 上と同じように、printの実行時には式の持つ値が表示されます。

nenrei = 19
print (nenrei <20)

nenrei = 21
print (nenrei < 20)

2つの条件判定式がそれぞれどのような値を持つか考えてみましょう。 わからない人はもう一度、前の解説を読んでみましょう。


比較演算子

if文の条件判定式で使用する < や > のことを比較演算子と呼びます。 比較演算子には次のような種類があります。

a == baとbは等しい
a != baとbは等しくない
a < baはbより小さい
a > baはbより大きい
a <= baはb以下
a >= baはb以上

課題2-2

次のようなプログラムを実現しなさい。
キーボードから整数を入力し、それが偶数なら、『その数は偶数です』と表示をし、 そうでなければ『その数は奇数です』と表示をするプログラムを作成しなさい。
具体的な応答の例です。
思いついた整数をキーボードから入力し、最後にエンターキーを押してください。
数:19
その数は奇数です
思いついた整数をキーボードから入力し、最後にエンターキーを押してください。
数:12
その数は偶数です
[偶数と奇数の判定]
偶数とは2で割り切れる整数、奇数とは2で割り切れない整数のことでした。 ですから、ある数が偶数か奇数かは、その数を2で割った余り(剰余)を求めればわかりますね。

ランダムな数の生成

randomint(min,max)は最小値min、最大値maxの間の整数をランダムに発生させる乱数生成関数です 。ただしこの関数をつかえるようにするには、次の命令を初めに実行する必要があります:

from random import randint
ランダムな数の集まりのことを乱数ともいいますが、乱数はプログラミングではとても重要で役に立つものです。 実際、乱数を使ったプログラムがたくさんあります。
[from ... importとは]
Pythonが起動した時にあらかじめ組み込まれている関数とは別に「モジュール」と言って関数や定数などのライブラリが用意されており、そのモジュールを組み込んでプログラムを書くことができます。そのための方法が import 命令です。おおよそ次の3つの方法があります:
import random
from random import randint
from random import *
上のいずれの方法でも randomモジュールで定義されているrandint関数が使えるようになります。ただし、import randomを使った場合は、random.randintとして関数を呼び出さないといけません。また、3番目の方法では、randint以外にrandomモジュールで用意されている関数がすべて組み込まれてしまう、ということがあります。

次の課題で、さいころの目を出すプログラムをこのrandint関数で実現してみましょう。

課題2-3

次のように、実行するたびごとにサイコロの出る目がランダムに変わるプログラムを実現しなさい。
H:>Python program.py
さいころを振ります!
コロ,,,  #0.3秒づつ待つ。
コロ,,,  #0.3秒づつ待つ。
コロ,,,  #0.3秒づつ待つ。
         #0.5秒待つ。
さいころの目は3でした。

H:>Python program.py
さいころを振ります!
コロ,,,  #0.3秒づつ待つ。
コロ,,,  #0.3秒づつ待つ。
コロ,,,  #0.3秒づつ待つ。
         #0.5秒待つ。
さいころの目は5でした。
[n秒間待たせるには]
sleep関数を使います。これを使うには、次の命令を初めにしておく必要があります:
from time import sleep
これにより、次のようにすれば、最初の表示と次の表示との間に0.3秒間の間をあけることができます:
print (u"コロ,,,")
sleep(0.3)
print (u"コロ,,,")

課題2-4

これまでに学んだことを応用して、次のようなサイコロゲームを作成しなさい。
#当たった時
さいころゲームの始まりです!
次に振ったさいころの目を当てましょう。
次にでる目はなんですか?
予測:5
では振ります。
コロ,,,  #0.3秒づつ待つ。
コロ,,,  #0.3秒づつ待つ。
コロ,,,  #0.3秒づつ待つ。
サイコロの目は?  #0.5秒待つ。
5 でした!
大当たりです! 超能力をもっていますね。
#はずれた時
さいころゲームの始まりです!
次に振ったさいころの目を当てましょう。
次にでる目はなんですか?
予測:5
では降ります。
コロ,,,  #0.3秒づつ待つ。
コロ,,,  #0.3秒づつ待つ。
コロ,,,  #0.3秒づつ待つ。
サイコロの目は?  #0.5秒待つ。
2 でした!
残念でした。また挑戦してくださいね。

[作成のヒント1:プログラムの流れ]

さいころの目はrandint(1,6)で作り出せます。
ゲームの参加者の予測はキーボード入力から取り出せます。
上の二つが同じかどうかの判定とそれに従った分岐はif文の条件分岐でできます。
num1とnum2が同じかどうかは、(num1 == num2 )という条件判定式でできます。

[作成のヒント2:変数をうまく使う]

変数に値(数など)をとっておけば、後で必要になった時に使えます。

[作成のヒント3:文字列と数の違いに注意]

input() は、文字列を返すのであって、数を返すものではありません。入力した文字列をそのまま使ってもよいですが、ここではまず入力文字列を数に変換してから、サイコロの目とユーザーの予測とを比較するようにしましょう。

より複雑な条件分岐(if文)を理解する

if文はプログラムを場面に応じて適切に動作させるためになくてはならない ものであり、プログラミングの基本の一つであることは上で述べました。 より 複雑なif文を持つプログラムの理解と作成に挑戦してみましょう。 上で学んだように、if文の基本的な構造は次のようなものです。
if (条件判定式):
    文1
    文2
    ...
else:
    文100
    文101
    ...
ifとelseというキーワードに条件判定式を合わせたものと、実行される文の集まりの二つから構成されています。 前に出した同じ具体例で、もう一度確かめておきましょう。
nenrei = 21

if (nenrei >= 18):
  print (u"あなたは車の免許を取ることができます。")
else:
  print (u"あなたはまだ車の免許を取ることができる年齢に達していません。")
ifの隣にある括弧の中は条件判定式です。この括弧の中の式が実行され、値が真であれば、次の行の文1、文2などが順番に実行されて終わります。 条件判定式を実行した結果の値が偽であれば、elseの下の実行文100、実行文101などが順番に実行されます。 つまり、条件判定式の値によって、実行される文(の集まり)が違う、ということが大事な点です。

さて、基本は同じですが、もう少し複雑なif文を見てみましょう。 if文全体も一つの文ですから、次のようにif文の実行式1のところに、if文を入れることで、つぎのようにより複雑な分岐を実現することができます。 Pythonプログラムとして、内側のif文はさらに何文字分かスペースを前にいれることが大事です。

  if (条件判定式):        # 最初のif。この前に2個のスペースがあるとする
    if (条件判定式):         # 最初のifの中のif文。4個のスペースを置く # 2番目のif文が真の場合に実行される文。スペースを6個置く # 2番目のif文が真の場合に実行される文。スペースを6個置く 
      ...
    else:	             # 2番目のif文と対になるelse文. if文と同じ4個のスペースを置く # else文を構成する文。6個のスペースを置く
      文
      ...                               # else文を構成する最後の文
  else: 	          # 1番目のif文と対になるelse文. if文と同じ2個のスペースを置く # else文を構成する文>
    文
    ...                      # else文を構成する最後の文>
ここで、プログラムの先頭に置くスペースの個数に注意してください。 最初のif文の前にスペースが2個書いてあったとすると、2行目にあるif文の前には4個のスペース、その次の「文」には6個のスペースをおきます。 そしてこれは6行目のelseの前の「文」まで、同じ個数のスペースを書かないといけません。 また6行目のelseの前には4個のスペース、その次の「文」には6個のスペースを起きます。 このように、先頭におくスペースの個数でプログラムの構造を指示しています。

次のようなプログラムがその具体的な応用例です(ここでは先頭のif文の前にはスペースはありません):

# -*- coding: utf-8 -*-
print (u"年齢を数字でキーボードから入力してください。")
nenrei = int(input())

if (nenrei >= 18):
  if (nenrei >=20):
    print (u"あなたは車の免許を取ることができます。")
    print (u"あなたはお酒も飲むこもできます。")
    print (u"よかったですね!")
  else:
    print (u"あなたは車の免許を取ることができます。")
    print (u"しかし、あなたはお酒を飲むことは法律で禁じられています。")
    print (u"残念でしたね!")
  # if (nenrei >= 20)
else:
  print (u"あなたは残念ながらまだ車の免許を取ることができる年齢に達していません。\nお酒も飲んではいけません。")
# if (nenrei >= 18)

if文は自由に組み合わせて構成できますから、さまざまな変形の形があります。 elseがないものも可能です。

if (条件判定式):
  文
  文
  ...

また、次のように、if文の中にif文のつながりがあってもよいことになります。

if (条件判定式):
   if (条件判定式):
     文
     文
     ...
   if (条件判定式):
     文
     文
     ...
   else:
     文
     文
     ...
   文
   文
   ...

課題2-5

次のプログラムがどのように振舞うのか、まずstar.pyという名前のファイルに書き出し(utf-8を指定すること)、プログラムをじっくり読んで予測しなさい (実行して調べてははだめです)。 その後、python star.pyを実行して、予測と合ったかどうか報告しなさい。
# -*- coding: utf-8 -*-
print (u"数を入力してください> ",)
kazu = int(input())

if (kazu == 1):
  print (u"☆")
else:
  if (kazu == 2):
      print (u"☆☆")
  else:
    if (kazu == 3):
        print (u"☆☆☆")
    else:
      if (kazu == 4):
        print (u"☆☆☆☆")
      else:
        print (u"★")
      # if (kazu == 4) ... else
    # if (kazu == 3) ... else
  # if (kazu == 2) ... else
# if (kazu == 1) ... else

elif文

今のプログラムでは else のあとに if文が現れていました。図示すると次のようになっていました。
if (kazu == 1):
  文1
else:
  if (kazu == 2):
    文2
  else:
    if (kazu == 3):
        文3
    else:
      if (kazu == 4):
        文4
      else:
        文5
      # if (kazu == 4) ... else
    # if (kazu == 3) ... else
  # if (kazu == 2) ... else
# if (kazu == 1) ... else
この場合は、変数kazuの値がなにかによって実行する文が選ばれています。
このようにelseの中にif文が埋め込まれる場合はよくあります。 Pythonではこのような場合、次のように elif 文によって見やすく(?)書くことを許しています。
if (kazu == 1):
  文1		# kazu==1の場合に実行される
elif (kazu == 2):
  文2		# kazu==2の場合に実行される
elif (kazu == 3):
  文3		# kazu==3の場合に実行される
elif (kazu == 4):
  文4		# kazu==4の場合に実行される
else:
  文5		# それ以外の場合に実行される
# if ... else文の終わり

課題2-6

課題2-5のプログラムをelif文を使って書き直しなさい。 またこれを実行して課題2-4のプログラムと同じ結果を返すことを確認しなさい。

繰り返しの基本を学ぶ

プログラミングをする上で頻繁に使う最も重要な基本パターン は「繰り返し」の構造だと 言っても言い過ぎではないでしょう。 コンピューターが強力な道具であるのは、それが高速であるため ですが、その高速性を生かして役に立つ道具にするためには、これから説明する 「繰り返し」の構造が本質的な役割を果たしています。 現実のほとんどのプログラムが繰り返し構造を使っていると言ってもよいでしょう。

次のように、「こんにちは」を10回表示するプログラムを考えてみましょう。

こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは
こんにちは

これまでは、print文を10個書く必要がありました。

print (u"こんにちは")
print (u"こんにちは")
print (u"こんにちは")
print (u"こんにちは")
print (u"こんにちは")
print (u"こんにちは")
print (u"こんにちは")
print (u"こんにちは")
print (u"こんにちは")
print (u"こんにちは")

繰り返し構造を実現するforwhile を使うことで、上のプログラムを次のように短く簡潔に書くことができます。

なぜ、これでうまくいくのか、その仕組みを理解しましょう。 仕組みを理解することは大事です。 そうしないと、大事なくり返しの構文を自由自在に使いこなせないからです。

2種類の繰り返し: forとwhileの特徴

Pythonではいろいろな種類の「繰り返し」の構文が用意されています。 その中でforwhile はとても重要です。これは2つの違う考えに基づく繰り返しを実現するからです。

forは、「ある決まった回数だけ」 (もしくは決まった個数の対象に対してだけ)、命令を繰り返します。 今の例はprint命令を10回繰り返すという問題でしたから、for文を使うには最適の問題でした。

whileは、「ある条件が成り立っている間」だけ命令を繰り返します。 今の例はprint命令を10回繰り返すという問題でしたから、while文を使うにはあまり適さない問題でした。

for文の仕組み

forというキーワードを使った繰り返しの構文は次のような形をしています。
for 変数 in 変数の取りうる範囲の指定:
     文1
     文2
     ...
# for 文の終わり 

ここで「変数の取りうる範囲の指定」によく用いられる関数rangeについて簡単に説明します。forの中のrangeはrange(n)のように引数1個(nは正整数)で使われると、最小値0、最大値n-1までの範囲の整数を返します(要するに、n個の整数が返されます)。また、 range(min,max)のように引数2個(min < max、整数でないといけない)で使われると、最小値min、最大値max-1までの整数を返します。

ですからこのfor文を実行すると、次のように動作が行われます。

1. まず変数の値として「変数の取りうる範囲の最小値」が与えられる。
2. 変数の値が「変数の取りうる範囲の上限値」以上であれば、for全体の実行を終える。
3. 文1, 文2, ...が順番に実行される。
4. 変数の値に1が足され、プログラムの実行が2.に戻り、もう一度同じことが繰り返される。
先ほどの「こんにちは」を10回表示するfor構文を使ったプログラムが働く上で大事なことは、 繰り返しを制御する変数が必要なことです。変数iの値の変化を表すよう書きなおした 次のプログラムを実行させてみてください。

for i in range(10):
  print (i+1, u"回目のこんにちは")
# for 

ここで変数としてiを使いましたが、変数として使えるものならなんでも構いません。 ただこの変数がないと、繰り返しはうまく機能しません。 なお、変数iのとりうる範囲をrange(10)と書いていますが、これはもちろん 最小値が0,上限値が10であることを表しています。 ちなみに、単に10回「こんにちは」をprintするだけでしたら、 最小値が1001で最大値が1010でも構いません(変数iがとる値は1001から1010までの10通り)。 実際、次のようにも書けます(が、プログラムがわかりにくくなりますので、普通はやりません)。

for i in range(1001,1011):
  print (u"こんにちは")
# for 文の終わり

課題3-1

次の結果を出力するプログラムを、for文を使って実現しなさい。
2
4
6
8
10
12
14
16
18
20

課題3-2

次の結果を出力するプログラムを、for文を使って実現しなさい。
20
18
16
14
12
10
8
6
4
2

[ヒント:課題3-1, 3-2のように数を表示するにはどうしたらいい?]

色々なやり方があります。課題3-1では1,2,...,10のそれぞれの値に対して2倍したものをprintすればよいし、課題3-2では課題3-1を使って、その値を22から引けばできるでしょう。

別なやり方としては、新たなrangeの使い方があります。rangeには先ほどの説明以外に、 range(初期値、上限値、刻み値)と、3つの引数を与えることができます。 ここで刻み値は1に限らず、整数ならどんな数でもよく、負の数でもよい(ただし、負の数の場合、初期値 > 上限値でないといけない)のです。

>>> range(1,10,2)                    # >>>はPythonのプロンプト
[1, 3, 5, 7, 9]
>>> range(10,-5,-2) 
[10, 8, 6, 4, 2, 0, -2, -4]

while文の仕組み

whileというキーワードを使った繰り返しの構文は次のような形をしています。

while (条件判定式):
  文1
  文2
  ...
# while文の終わり 

whileを実行すると次のように動作します。

1. まずif文と同様、条件判定式が実行され、その値が取り出される。
  1-1. 条件判定式の値がの時、
         その下の文1、文2などが順番に実行される。(この辺りはif文と同じです。)
         while文の最後まで来ると、プログラムの実行場所がwhileの先頭に戻る。
         (1. に戻り、条件判定式がもう一度実行され、同じことが繰り返される。)
  1-2. 条件判定式の値がの時、
         何もしないで、while全体の実行を終える。(2. に進む。)
2. while文の次の文から実行を再開する。

先ほどの「こんにちは」を10回表示するプログラムをwhile構文を使って書くには、 表示される回数を数えるための変数が必要になります。以下ではその変数として iを用いています。そして、while文の前に変数iに0を与え、 表示が終わるごとにiに1を足すようにしています。変数iの値の変化に着目してください。

i = 0          #iの値は0。
while (i < 10):
  print (u"こんにちは")
  i = i + 1    #iの値を1つ増やす。
# while 文の終わり

10回繰り返して、そこで終わりになるのは、繰り返すたびごとにiの値が1ずつ増えていることと、 条件判定式 (i < 10) のおかげです。 10回繰り返すまでは、iの値は10より小さいので、条件判定式が真となり、繰り返しを行うことになります。 10回以上になると、条件判定式が偽となりますので、whileの実行を止めることになります。
このように、回数を記憶するための変数 (このような変数をカウンター変数と呼びます)には、 whileの繰り返しに入る前に0などの数を代入しておく必要があります。 この変数の働きがないと、while文を使ってある一定の回数繰り返す、というプログラムはうまく機能しません。

課題3-3

次の結果を出力するプログラムを、while文を使って実現しなさい。
3
9
27
81
243

課題3-4

次の結果を出力するプログラムを、while文を使って実現しなさい。
20
18
16
14
12
10
8
6
4
2

課題3-5

次の実行結果に示されるように、 最小値と最大値をそれぞれキーボードから入力し、その間の数をすべて足した 合計を返すプログラムをfor文とwhile文、それぞれを使って書きなさい。 (オレンジ色の文字はキーボードからの入力を 表しています。キーボードから数の入力を受け取る方法は、 ここを参照してください。)

数の合計を計算します。数を入力してください。
最小値:10
最大値:30
10から30までの数の合計は420です。

for文とwhile文のどちらのほうが書きやすかったでしょうか?またその理由は何でしょう。

課題3-6

nを正の整数とした時、階乗n!を計算するプログラムを作成しなさい。 (注意: n=5ならn!=5!=120となります。しかし! という演算子はありません。これは「数学」の記法です)
次の例のように、nはキーボードから入力するものとし、 階乗を計算した結果を以下のように出力するようにしなさい。
以下はnが100の時の例です。

コンピュータ:自然数nの階乗の計算を行います。nをキーボードから入力し、Enterキーを押してください。
n:20
結果:20の階乗は2432902008176640000です。

[ヒント:階乗の意味]

nの階乗の意味は次の通りです。

n * (n-1) * (n-2) * ... * 3 * 2 * 1 
これを数学では n! と書きます。
例
5! = 5 * 4 * 3 * 2 * 1 = 120

無限に繰り返す

回数を限定しないで繰り返すためには、

while (True):
  ...
  ...
  ...
# while文の終わり 

というような形が使えます。条件判定式の中が常にTrue(真)なので、終わりません。

このような「終わらない」while文は上の形以外にも、カウンタ変数の更新式 (i=i+1のような式)を書き忘れた場合に出現します。 これを無限ループと言います。無限ループに陥ったプログラムを止めるのは コントロールC(Ctrlキーを押したままCを押す, Ctrl-Cと書く)です。以下を実行し、プログラムをCtrl-Cで止めてみましょう。

while(True): print(".")

Pythonのデータ構造

文字列

Pythonでは文字列とは、一文字一文字の並びです。それを一重引用符(')か二 重引用符(") でくくって、Pythonでは文字列として扱えるようになります。 一重引用符と二重引用符はどちらを用いても構いません。文字列の中に引用符を含む場合、それがその文字列をくくっている記号と異なる場合はそのまま書いて良いが、同じ記号の場合、バックスラッシュ(\、ただし日本語モードでは\ではなく円記号\で表示される)を前に置きます。
>>>  x = "John's store"				# "と"でくくられた文字列の中に'を書く場合
>>>  y = 'Mary\'s favorite fruit'		# 'と'でくくられた文字列の中に'を書く場合
>>>  print ( "I bought ", y, " at ", x)
I bought Mary's favorite fruit at John's store
文字列の長さは、関数 len で与えられます。ここで、''は文字が含まれない特殊な文字列で、空文字列といいます。
>>>  len('abc')
3
>>>  len('')
0
文字列には添字(インデックス)付けをすることができる。Cと同様に添字は0から始まります。
>>>  fruit = 'apple'
>>>  fruit[0]
'a'
面白いことに添字に負の数が使えます。これは文字列を後から数えることを示します。
>>>  fruit[-1]
'e'
添字としてm:nという指定ができます。これはm文字目からn-1文字目までの部分文字列の指定となります。ここでmの部分を省略して ;nと書いた場合は0文字目からと解釈され、nの部分を省略した場合は、最後の文字までと解釈されます
>>>  fruit[2:4]		# 2文字目から(4-1)=3文字目までの部分文字列
'pl'
>>>  fruit[:2]		# 先頭(0文字目)から(2-1=)1文字目までの部分文字列
'ap'
>>>  fruit[2:]		# 2文字目以降の部分文字列
'ple'
Cと異なり、文字列は変更不可能です。つまり、文字列中の添字で指定した位置に代入しようとするとエラーになります:
>>>  fruit[2] = 'o'		# 2文字目を'o'で置き換えようとする
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'str' object does not support item assignment
なお、任意の型の値を文字列にする関数strが用意されている。例をみて使い方を学びましょう:
>>>  str(2*5)
'10'
>>>  str([2,5])					# [2,5]はリスト
'[2, 5]'
>>>  str((1,2,3))				# (1,2,3)はタプル
'(1,2,3)'
ちなみに、文字列を数にする関数としては intとfloatがあります。前者は文字列を整数に、後者は実数(浮動小数点数)に変換します。ただし、変換できるのは、数に相当する文字列に限ります。ここで、intは第2引数として『基数』を指定できます。例により説明します。
>>>  int(' 3 ')		# 整数の文字列
3
>>>  int('3.14')		# 実数の文字列はエラーになる
Traceback (most recent call last):
  File "", line 1, in 
ValueError: invalid literal for int() with base 10: '3.14'
>>>  int('3A',16)		# 第2引数として16を指定すると、16進数表示と解釈される
58
>>>  float('3.14')		# intの場合はエラーになるがfloatの場合は実数に変換される
3.14
[int('3A',16)について]
10進法では0から9までの数を使いますが、16進法ではそれに加えて、10位上の数を表すのにアルファベット(A, B, C, D, E, F)を用います。そして、Aは10、Bは11, …、Fは15を表します。
10進法で35と表されるのは 3×10 + 5という数であると同様に、 16進法で'3A'と表されるのは、10進法で表すと 3×16 + A です。つまり 48 + 10 = 58 という数です。

なお、intの第2引数には16以外の整数も指定できます。 2進数や8進数の計算に便利です。

リスト

ここではリスト(Cにおける配列に相当)について学びます。 リストはプログラミングには欠かせない最も重要な基本要素、 基本的な「データ構造」の一つです。 リストをマスターしない限り、現実のプログラミングはできないと言っても言い過ぎではありません。 繰り返しがコンピューターの力のもとだといいましたが、リストと一緒に使うことで、 コンピューターはますます強力になると言ってもよいでしょう。

それでは、リストとはどんなものでしょうか。たくさんのものをしまったり出したりできる、便利な入れ物です。ここまでは変数と同じように、入れ物として働いているだけですが、変数と違って、一つだけではなく、たくさんのものを入れたり出したりして処理することができます。 変数の集まりであると考えることもできます。 変数に値を入れることができるということは、変数がいろいろな値を取れるということになります。 (変数という言葉の由来です。)リストは複数の変数の集まりと見ることができ、したがって、複数の値を扱うことができるのです。 変数は変数名によって保持している値を扱いますが、 リストでは、次に述べるような形で、名前で直接値を扱うのではなく、指標(インデックス)といわれる数によって、 値を扱うことができるのです。これが変数をとても便利に使える大きな理由の一つでしょう。 このようなことが何を意味するのか、下の例で一歩、一歩見て行きましょう。

リストの特徴を複数の変数を使う場合と対比してしてみましょう。いつくもの名前と挨拶を扱うプログラムを、リストを使わないで、変数だけで作ってみましょう。 まず、用意した nameA,nameB,nameC,nameD,nameEという5個の変数に、 名前を表す文字列を代入しておきます。それを次々に出力していくことにします。

nameA = u"太郎"
nameB = u"紘美"
nameC = u"克規"
nameD = u"倫哉"
nameE = u"隆弘"

#ここまでで、変数への名前の代入ができました。
#これから後は出力です。

print (u"こんにちは、", nameA, u"さん")
print (u"こんにちは、", nameB, u"さん")
print (u"こんにちは、", nameC, u"さん")
print (u"こんにちは、", nameD, u"さん")
print (u"こんにちは、", nameE, u"さん")
このプログラムを実際に、実行してみてください。

今度は、変数ではなく、リストの中に上の5個の名前を入れます。 まず、nameという変数を用意します。そして変数nameに、今の要素を値とするリストを代入します。これは、次のようにすればできます。

name = [u"太郎", u"紘美", u"秀樹", u"倫哉", u"隆弘"]      #  変数nameにリストを代入
リストは、Pythonだけでなく、多くの言語で[ ]を使って表すことが普通です。 次が肝心なところですが、番号を表す数(これを指標、インデックスともいいます)で、要素を取り出すことができます。
>>> for i in range(len(name)):
....   print (u"こんにちは、", name[i], u"さん")         # .... は継続行であることを表す
こんにちは、太郎さん
こんにちは、紘美さん
こんにちは、秀樹さん
こんにちは、倫哉さん
こんにちは、隆弘さん
ここでlen(name)は、リストnameの要素数を返します。ここでは5です。 ですからrange(len(name))range(5)と同じです。 つまり、iの値は0,1,2,3,4という値を順にとります。

指標は0以上の整数であることに注意してください。 これは、リストが0番から始まるということであり、 「リストの一番最初の要素の指標が0」ということです。

ここで、

print (name[2])
を実行すると、どんな出力結果が出てくるでしょう?
秀樹
が出てきます。name[2]の値は"秀樹"なので、当然ですね。

それでは次を実行するとどんな出力結果になるでしょう。

name[2]=u"一郎"
print (name[2])
1行目で指標2の要素(0から指標が始まるので、要素としては3番目)が"一郎"に書き換えられています。ですから、答は"一郎"です。

なお、空っぽのリストを用意して、それに次々と要素を付け加えていくことでも、同じことが実現できます。

name = []                        # 空っぽのリスト
name.append(u"太郎")             # "太郎"を付け加える
name.append(u"紘美")             # "紘美"を付け加える
name.append(u"秀樹")             # 以下同様
name.append(u"倫哉")  
name.append(u"隆弘")  
こうしてできたリストnameが、先のnameと同じリストであることを確かめてみてください。

課題4-1

以下では、nameという変数の中のリストには名前を順番に入れておきます。 プログラムを実行すると、何が出力されるのか予測して報告しなさい。 そのあと、実際に実行して、予測と合ったかどうか報告しなさい。 予測と合わなかったら、その理由も報告すること。

name  = []

name[0] = u"太郎" 
name[1] = u"紘美" 
name[2] = u"秀樹" 
name[3] = u"倫哉"
name[4] = u"隆弘"

i = 3
print (name[i])

リストがプログラミングの強力な道具になるのは、数(指標)によってリストの内容を取り出せるからです。 forやwhileの繰り返し文と組み合わせて使うことでリストは特に便利になります。

リストには、文字列に限らず何でも、入れることができます。 (変数に何でも入るのと同じです。)数を扱ってみましょう。

data = [2,4,7,3,9,6,4,4,10,23,1,1,1,7,8,6,25,30,30,9] 

課題4-2

次のプログラムを実行すると、何が表示されるのか予想し、その予想を報告しなさい。
data = [2,4,7,3,9,6,4,4,10,23,1,1,1,7,8,6,25,30,30,9] 

print (len(data))

print (data[0])
print (data[4])
i = 5
print (data[i])
print (data[i+3])

課題4-3

繰り返し(forまたはwhile)を使って、次のリストの内容をそのまま、以下のように出力するプログラムを作成しなさい。
data = [2,4,7,3,9,6,4,4,10,23,1,1,1,7,8,6,25,30,30,9] 
2
4
7
3
#(中略)
30
9

課題4-3

次のプログラムはリストの要素の数を合計して結果を出力しようとして、 作ったものですが、完全なものではありません。 実際に実行しながら、誤りを見つけて、正しいプログラムを完成させなさい。 まず、このまま実行してみて何が表示されるのか見てから考えてみてください。
data = [2,4,7,3,9,6,4,4,10,23,1,1,1,7,8,6,25,30,30,9] 

total = 0
for i in len(data):
  total = data[i]
# for

print (u"リストの合計は", total, u"です。")

出力結果は次のようになります(なるように直しなさい)。

リストの合計は190です。

参考: Pythonではsumという関数があります。sum(data)を試してみましょう。ただし上の答えにはこの関数を使わずに答えなさい。

for再訪---リストとの組み合わせ

リストはfor文を使うと、簡単に扱えることがあります。次のような形で扱います。

data = [e0, e1, ... , en]
for ele in data
  文1
  文2
  ...
# for文の終わり 

for文を理解する上でのポイントは、inの前の変数です。代入文が明示されていませんが、 リストの中からその要素が一つ一つ取り出されては、eleに代入され、実行されることを繰り返します。

何回繰り返し実行されるのかという回数は、リストの要素の数と同じになるのは当然です。このような繰り返しのやり方は、指標(インデックス)を使わずにリストの要素を直接扱えるという特徴があります。

[rangeが返す値]
2種類の繰り返しの項でrangeを紹介した時、 「rangeはrange(n)のように引数1個(nは正整数)で使われると、最小値0、最大値n-1までの範囲の整数を返します(要するに、n個の整数が返されます)」と述べました。 実際にどのような値が返されるかを見てみましょう:
>>> range(5)
range(0,5)
実はPython3からrangeが返す値が不思議なものになっています。 これはジェネレータと言い、rangeは呼ばれる度に数を返します。 ですが、次のようにすれば、rangeの値をリストとして確認できます。
>>> list(range(5))
[0,1,2,3,4]
つまり次の繰り返し:
for x in range(5):
   print (x, x**2, x**3)
は、実際には次のコードと同値だったわけです:
for x in [0,1,2,3,4]:
   print (x, x**2, x**3)

課題4-4

課題4-3で作成したプログラムを、指標を使わない方法で書き直しなさい。

リストの中から必要なものだけを取り出して処理する

リストの中から必要なものだけを取り出して、処理する形はよくあるプログラムの「パターン」です。 このパターンに慣れておく必要があります。if文とうまく組み合わせることがこつです。

数の大小の判定などは、次の式でできます。
a == baとbは等しい
a != baとbは等しくない
a < baはbより小さい
a > baはbより大きい
a <= baはb以下
a >= baはb以上

また、一つの条件式で書けない複雑な条件式(真偽の値の合成)は、 論理演算子と呼ばれるものを使って、条件を組み合わせて表現します。

「かつ」(and)は andで表現され、「または」(or)は or で表されます。 これらは条件と条件の間に書きます。 また、「でない」(否定, not)は not で表し、条件の前に書きます。 プログラミング言語Cで用いられている&& や || や !はPythonでは使えませんので注意してください。

A and BAかつB
A or BAまたはB
not A Aでない

例えば、「numが3以上でかつ10以下」という条件式は、次のようになります。

(num >= 3 and num <= 10)

また、「numが3または10」という条件式は、次のようになります。

(num == 3 or num == 10)

さらに、『「nが3以上で mが10以下」でない』という条件式は、次のようにかけます。

not (n >= 3 and m <= 10)

注意: リストの内包記法を使わずに答えなさい。

課題4-5

次のリストの中から、10以上、20以下の数をとり出し、表示するプログラムを作成しなさい。

numbers = [4,12,45,21,18,7,20,5,51,16,10]
#この後の部分を作る

出力は以下のようになる。

12
18
20
16
10

課題4-6

上の課題で、今度は10以上、20以下の数をとり出すのではなく、取り出した数だけ合計し結果を出力しなしなさい。
出力は以下のようになる。

10以上、20以下の数の合計は76です。

課題4-7

上の課題で、今度は10以上、20以下の数の合計ではなく、そのような数が幾つあったのかを数え、その数を出力しなしなさい。
出力は以下のようになる。

10以上、20以下の数は全部で5個あります。

課題4-8

以下のnekodataという変数の中のリストにはたくさんの「ねこ」が入っています。この中から、プログラムを作って、"とらねこ"を探し出して、何匹いるのか、その数を報告してください。以下のnekodataという変数にリストを代入する部分をプログラムの頭にコピーして使ってください。

nekodata = [u"しろねこ", u"みけねこ", u"みけねこ", u"しろねこ", u"しろねこ", u"みけねこ", 
 u"しろねこ", u"みけねこ", u"みけねこ", u"しろねこ", u"みけねこ", u"しろねこ", u"みけねこ",
 u"みけねこ", u"しろねこ", u"くろねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"みけねこ",
 u"しろねこ", u"くろねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"しろねこ",
 u"みけねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"しろねこ", u"みけねこ", u"しろねこ",
 u"くろねこ", u"しろねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"みけねこ",
 u"しろねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"くろねこ", u"くろねこ",
 u"しろねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"しろねこ", u"くろねこ",
 u"くろねこ", u"くろねこ", u"みけねこ", u"しろねこ", u"くろねこ", u"みけねこ", u"しろねこ",
 u"しろねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"くろねこ", u"みけねこ", u"みけねこ",
 u"しろねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"みけねこ",
 u"しろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"くろねこ", u"しろねこ",
 u"くろねこ", u"みけねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"しろねこ", u"みけねこ",
 u"みけねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"しろねこ",
 u"くろねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"しろねこ", u"くろねこ", u"みけねこ",
 u"しろねこ", u"くろねこ", u"みけねこ", u"くろねこ", u"くろねこ", u"みけねこ", u"みけねこ",
 u"しろねこ", u"くろねこ", u"みけねこ", u"みけねこ", u"くろねこ", u"みけねこ", u"しろねこ",
 u"みけねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"くろねこ",
 u"みけねこ", u"みけねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"みけねこ", u"しろねこ",
 u"しろねこ", u"しろねこ", u"みけねこ", u"くろねこ", u"くろねこ", u"みけねこ", u"くろねこ",
 u"みけねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"くろねこ", u"くろねこ",
 u"くろねこ", u"くろねこ", u"みけねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"とらねこ",
 u"しろねこ", u"とらねこ", u"とらねこ", u"くろねこ", u"みけねこ", u"しろねこ", u"とらねこ",
 u"しろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"みけねこ", u"とらねこ",
 u"くろねこ", u"みけねこ", u"みけねこ", u"くろねこ", u"くろねこ", u"みけねこ", u"しろねこ",
 u"しろねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"しろねこ", u"くろねこ", u"みけねこ",
 u"みけねこ", u"とらねこ", u"みけねこ", u"とらねこ", u"みけねこ", u"しろねこ", u"しろねこ",
 u"みけねこ", u"くろねこ", u"くろねこ", u"みけねこ", u"しろねこ", u"くろねこ", u"みけねこ",
 u"とらねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"しろねこ", u"くろねこ",
 u"みけねこ", u"みけねこ", u"みけねこ", u"くろねこ", u"くろねこ", u"しろねこ", u"くろねこ",
 u"みけねこ", u"みけねこ", u"くろねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"くろねこ",
 u"みけねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"くろねこ",
 u"くろねこ", u"しろねこ", u"ばけねこ", u"みけねこ", u"くろねこ", u"くろねこ", u"みけねこ",
 u"しろねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"くろねこ", u"みけねこ", u"くろねこ",
 u"しろねこ", u"くろねこ", u"みけねこ", u"しろねこ", u"とらねこ", u"しろねこ", u"しろねこ",
 u"みけねこ", u"くろねこ", u"うみねこ", u"しろねこ", u"みけねこ", u"しろねこ", u"みけねこ",
 u"みけねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"しろねこ",
 u"くろねこ", u"みけねこ", u"しろねこ", u"みけねこ", u"くろねこ", u"みけねこ", u"くろねこ",
 u"みけねこ", u"みけねこ", u"くろねこ", u"とらねこ", u"くろねこ", u"しろねこ", u"しろねこ",
 u"みけねこ", u"しろねこ", u"しろねこ", u"くろねこ", u"くろねこ", u"しろねこ", u"みけねこ",
 u"しろねこ", u"みけねこ", u"みけねこ", u"しろねこ", u"しろねこ", u"しろねこ", u"くろねこ",
 u"くろねこ", u"みけねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"とらねこ", u"しろねこ",
 u"くろねこ", u"みけねこ", u"くろねこ", u"うみねこ", u"しろねこ", u"くろねこ", u"しろねこ",
 u"みけねこ", u"しろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"しろねこ",
 u"みけねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"くろねこ", u"しろねこ",
 u"みけねこ", u"くろねこ", u"みけねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"みけねこ",
 u"みけねこ", u"くろねこ", u"みけねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"しろねこ",
 u"しろねこ", u"みけねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"しろねこ", u"みけねこ",
 u"しろねこ", u"しろねこ", u"くろねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"みけねこ",
 u"くろねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"くろねこ", u"しろねこ", u"みけねこ",
 u"くろねこ", u"みけねこ", u"みけねこ", u"みけねこ", u"くろねこ", u"くろねこ", u"みけねこ",
 u"くろねこ", u"とらねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"くろねこ",
 u"くろねこ", u"しろねこ", u"くろねこ", u"みけねこ", u"しろねこ", u"くろねこ", u"みけねこ",
 u"みけねこ", u"くろねこ", u"しろねこ", u"みけねこ", u"やまねこ", u"しろねこ", u"しろねこ",
 u"くろねこ", u"しろねこ", u"みけねこ", u"くろねこ", u"くろねこ", u"しろねこ", u"みけねこ",
 u"みけねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"みけねこ", u"しろねこ",
 u"くろねこ", u"みけねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"みけねこ",
 u"とらねこ", u"とらねこ", u"くろねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"くろねこ",
 u"しろねこ", u"くろねこ", u"くろねこ", u"くろねこ", u"みけねこ", u"くろねこ", u"しろねこ",
 u"しろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"くろねこ",
 u"しろねこ", u"しろねこ", u"しろねこ", u"しろねこ", u"しろねこ", u"みけねこ", u"みけねこ",
 u"しろねこ", u"くろねこ", u"あかねこ", u"くろねこ", u"みけねこ", u"みけねこ", u"しろねこ",
 u"みけねこ", u"みけねこ", u"しろねこ", u"くろねこ", u"しろねこ", u"くろねこ", u"くろねこ",
 u"くろねこ", u"みけねこ", u"しろねこ", u"みけねこ", u"みけねこ", u"みけねこ", u"しろねこ"]

[ヒント:文字列の異同の判定]

変数の中の文字列が同じかどうかなども、数と同様に==を使って判定できます。

  if (neko == u"くろねこ"):
    ...

プログラムの中で文字列を扱うには、"..."(ダブルクオート)で囲むことを忘れないこと。また日本語を含む場合は、u"ねこ" のようにuを先頭につけてください。

繰り返しから抜ける

これまで、繰り返しが終わるのは、whileの(条件判定式)を実行し、その値がFalseになったときだけでした。
これだけだと何かと不便なので、if文とbreakを組み合わせることで、繰り返しから脱出することができるようになっています。
break文を実行すると、(直前の) whileの繰り返しから抜けて、次に進みます。
注意: 繰り返しの中に繰り返しがあるような「入れ子になった繰り返し」の場合、 break文によって抜けられるのはそれを含む一番内側の繰り返しです。
次のように使います。

while (条件判定式):
  ...
  ...
  if (条件判定式):
    break
  else:
    ...
  # if … else の終わり
  ...
# while 文の終わり

[ヒント:breakの使い方]

次のように、breakを使えばよい。

while (...):
  ...
  nyuryoku = input()
  if (nyuryoku == 0):
    break
  else:
    print (u"... それではもう一回やりましょう。\n")
    sleep(2)
  # if ... else文の終わり
  ...
# while文の終わり 

課題4-9

課題4-8のnekodataの中に"あかねこ"があれば 「みつけた!」と表示してbreakを使って繰り返しをぬけ、 なかった場合は"いなかった"と表示するプログラムを作成しなさい。
この結果はどうなるでしょう。

課題4-10

課題4-9と同様に、nekodataの中に今度は"ぶちねこ"があれば「みつけた!」と表示してbreakを使って繰り返しをぬけ、 なかった場合は「いなかった」と表示するプログラムを作成しなさい。
この結果はどうなるでしょう。

リストの練習問題

ここではリストを使った、今までよりも少し難しい問題を扱います。 この問題を解くことによって、どのようにプログラムを組んだらよいか、 問題を解くためにこのプログラムではどういうことをどういう順番でさせていったらよいか、つまり、アルゴリズム を考える必要性が分かることでしょう。

課題4-11

数を要素とするリストの中から最大の要素を表示するプログラムを作成しなさい(ただしmax関数を使わないこと)。 例えば

data = [2,4,27,3,19,26,24,34,10,23,1,11,21,7,8,6,25,35,30,9] 
に対しては35が表示されます。

[ヒント:最大の要素を求めるアルゴリズム]

このプログラムには、リストを記憶する変数以外に、(途中までの)最大値を記憶するための変数が必要になります。それを仮に x とします。
まず最初に、xにリストの最初の要素をいれておきます。 そして、リストの要素をひとつずつxと比較し、それがxよりも大きければxの値をその値にします(更新する、という)。 リストの要素をすべて調べた後のxの値が求める最大の要素です。

なお、Pythonではmax関数が定義されており、この問題に対しては max(data)で答えが得られます。

課題4-12

課題4-11とは逆に、最小の要素を表示するプログラムを作成しなさい (ただし関数minを使わないこと) 。 課題4-12のdataの値では、1が表示されます。

課題4-13

数を要素とするリストの中から2番目に大きな要素を表示するプログラムを作成しなさい(ただし関数sortおよび sortedを使わないこと)。 例えば

data = [2,4,27,3,19,26,24,34,10,23,1,11,21,7,8,6,25,35,30,9] 
に対しては34が表示されます。ここで、dataの値が[1,2,3,3]のように最大値が2つあるリストの場合は、その中で2番目に大きな数、この例では最大値でもある3を返すものとします。

[ヒント:2番目に大きな要素を求めるアルゴリズム]

課題4-11や課題4-12では(途中までの)最大値や最小値を記憶するための変数(仮にxとします)が必要でした。 この課題では、それ「以外」に、2番目に大きな要素を記憶する変数が必要です。 それを仮に y とします。 まず、リストの先頭と2番目の要素の大きい方をx、小さい方を yとします。 そして、それら以外のリストの要素をひとつずつxおよびyと比較し、xとyの値を更新します。(ここでどういう比較をどういう順番で行えば効率がよくなるか、よく考えてください)。 リストの要素をすべて調べた後のyの値が求める2番目大きな要素です。

なお、sorted関数を使うとsorted(data)[1]で答えが出ます。

リストについて---知っておくと良いこと

プログラミング言語Cと異なり、便利なことに、リストの要素は同じ型である必要はありません。 つまり整数や不動小点数、文字列、リストなどが混じっていて良いのです。 また配列の要素数の宣言も限界もありません。つまり、あとで見るように、どんどん要素数を増やすことができます。

>>>  a = [1, 2.3, 'abc', ['a', 'b', 'c']]
>>>  a
[1, 2.3, 'abc', ['a', 'b', 'c']]
リストも文字列と同様に、0から始まる添字(インデックス)で要素を指定できます。そしてリスト同士を結合したり、(文字列とは異なり)要素を書き換えることができます。
>>>  a[0]			# 0番目の要素
1
>>>  a[-1]			# -1は最後の要素の指標
['a', 'b', 'c']
>>>  a[:3]			# 0番目から3-1(つまり2)番目の要素までのリスト
[1, 2.3, 'abc']
>>>  a[4] = 5			# 要素の書き換え:4番目の要素を5にする
>>>  a
[1, 2.3, 'abc', 5]
>>>  a[2:] = [4, 6, 8]		# 2番目以降をリスト[4,6,8]とする
[1, 2.3, 4, 6, 8]
文字列の長さを返す関数として紹介したlenは、リストの長さも返します。
>>>  len(a)
3
関数に似ているが、リストや文字列のような「データ型」それぞれに固有の「関数」をメソッドといいます。例えばリストにはsortやreverseというメソッドがあります。メソッドの呼出しは、その型のオブジェクト(を値とする変数)に続けてドット(.)をはさんでメソッド名を書きます。メソッドも広くは関数の一種なので、引数をとることもあります。ここでは例により、リストのメソッドを説明します。 (注意: 元の要素を書き換えてしまうsortに対し、 元の要素を書き換えずにソートした結果を返す sorted という関数もあります)
>>>  a = [5,1,3,2]		# 変数aの値としてリストをセット
>>>  a.sort()	           	# リストの要素を昇順にソートしたもので書き換える
>>>  a			# 変数aの値の確認
[1, 2, 3, 5]
>>>  a.reverse()		# リストの要素の並びを逆順にしたもので書き換える
>>>  a			# 変数aの値の確認
[5, 3, 2, 1]
>>>  a.append(10)		# リストに1個の要素を追加する(複数の要素の追加は不可)
>>>  a			# 変数aの値の確認
[5, 3, 2, 1, 10]
>>>  a.extend([8,6,4])        # リストに複数の要素を(リストを引数として)追加する
>>>  a			# 変数aの値の確認
[5, 3, 2, 1, 10, 8, 6, 4]
実際のプログラムではリストの要素をソートしたり並び順を反転する、という処理をよくおこないます。またリストの要素それぞれに対して何か処理をするのに for 文を用いる、ということも既に見たとおりです。ここで紹介するリスト内包記法は、この拡張版といえるものです。リストを加工して別のリストをつくる処理が簡単にできます。またこれにforを組み合わせて、さらにいろいろな処理をすることが簡単になります。

リスト内包記法は次のような形をしており、「計算式の結果」を要素とするリストができます:

  [  計算式  for  変数  in  シーケンス(リスト) ] 
例によって示しましょう:
>>>  [ x**2  for  x  in  range(10) ]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
この例では、 range(10)は [0,1,2,3,4,5,6,7,8,9]というシーケンス(リスト)を返します。そして、それぞれの値をxとして、計算x**2が行われ、その結果を順番に要素としたリストが作られたのです。なお、「シーケンス」の部分に次のように条件を付け加えることもできます:
>>>  [ x**2  for  x  in  range(10)  if x%3== 0]
[0, 9, 36, 81]
この例では、range(10)が返すシーケンスのうち、x%3==0が成り立つもの(つまり3で割り切れる0,3,6,9)だけについて x**2 が計算され、その結果を要素にしたリストが返されました。

ここで for の部分は複数かくことができます。それを例で示しましょう:

>>>  [ x**y for x in range(1,8) for y in range(1,4)]
[1, 1, 1, 2, 4, 8, 3, 9, 27, 4, 16, 64, 5, 25, 125, 6, 36, 216, 7, 49, 343]  
この例では計算式が x*y であり、xの値は for x in range(1,8)によって与えられ、yの値はその後の for y in range(1,4)で与えられています。その結果できたリストは、1**1, 1**2, 1**3, 2**1. 2**2, 2**3, ... 7**1, 7**2, 7**3 を要素とするリストです。

このリスト内包記法はとても便利でありよく使われます。それだけに他人が書いたプログラムで目にすることが多いので、慣れておくようにしましょう。

演習4.14

演習4.5〜4.7までの問題を、リストの内包記法を用いて解きなさい。

辞書(ディクショナリ)

Cにはないが、RubyやPerlのような他のプログラミング言語で「連想配列」や「ハッシュ」という名前で重宝されているのがこの辞書(ディクショナリ)です。これは一見するとリスト(配列)に似ていますが、リストではインデックスが整数であるのに対し、辞書では文字列や数値がインデックスとして使え、キーと呼ばれています。言い換えれば、リストが数というインデックスにより要素を取り出すのに対し、辞書ではキーによって「連想される」要素を取り出すのです。

辞書は、「キー : 値」という組の集まりを波括弧{ }でくくって表現されます。

>>>  gakusekiList = { 'taro': 3001, 'jiro': 3002, 'hanako' : 3003 }
この例では、'taro', 'jiro', 'hanako'がキーとして、それぞれ値3001, 3002, 3003とペアになった辞書が作られました。ここでgakusekiListにキーを与える(角括弧でくくる)とペアになった値が取り出されます。
>>>  gakusekiList['jiro']
3002
辞書の要素を書き換えたり、要素を追加するのは次のようにして行います:
>>>  gakusekiList['jiro'] = 3010		# キー'jiro'とペアの値を書き換える
>>>  gakusekiList['jiro']			# キー'jiro'とペアの値の確認
3010
>>>  gakusekiList['naomi'] = 3005        	# 新たなキー'naomi'と値とのペアの登録
>>>  gakusekiList				# gakusekiListの値の確認
{'naomi': 3005, 'hanako': 3003, 'taro': 3001, 'jiro': 3010}
最後の例から分かるように、キーと値のペアは辞書のなかでは登録された順番通りには入っていません(これはハッシュリスト、というデータ構造を知って入れば納得できるでしょう)。 辞書のキー全てからなるリストや、値からなるリストを取り出すためのメソッドとして、keysおよび valuesというメソッドが用意されています。また、あるキーが辞書にあるかどうかを調べるには in 関係演算子を使うのがよいでしょう。
>>>  gakusekiList.keys()
['naomi', 'hanako', 'taro', ', 'jiro']
>>>  gakusekiList.values()
[3005, 3003, 3001, 3010]
>>> 'naomi' in gakusekiList
True
>>>'saburo' in gakusekiList
False

演習4.15

単語を要素とするリストに対し、各々の単語の出現数をカウントして表示するプログラムを書け。つまりは次のようなことを実現する関数 countWords ができたらよい。

>>>  words = ['there', 'is', 'a', 'book', 'on', 'a', 'desk', 'that', 'belongs', 'to', 'me']
>>>  # ここにプログラムが入る---resultに、それぞれの単語と出現数とが辞書としてはいる
>>>  for x in result:  
          print (x, result[x])

a 2
on 1
to 1
that 1
(以下略)

[ヒント]

次のようにしてプログラムを考えるとよいでしょう:
  1. 変数resultに空っぽの辞書を値としてセットする。
  2. for文を用いて、wordsの要素一個一個を取り出し、resultに登録されているかどうか調べる
    例えば、 for x in words: とすればよいでしょう。
    • 登録されていなければ、その要素をキーとし、値を1として、辞書に登録する
      例えば x='book'で、この単語が未登録なら、 result[x]=1 とする。
    • 登録されいなければ、その要素をキーとした値に1を足して、辞書に再登録する
      例えば x='desk'で、この単語が登録されているなら、result[x] += 1とする。
  3. これが終了した時点で、resultにはwordsの単語がキー、その出現数が値となっているはず

タプル

値の並びをタプルといいます。
>>>  t = 'a', 1, 'b', 2, 3
>>>  print (t)
('a', 1, 'b', 2, 3)
>>>  type(t)
tuple
tの値の表示から分かるように、丸括弧で値の並びをくくっても、くくらなくてもどちらでも構いません。
>>>  t = ('a', 1, 'b', 2, 3)
>>>  print(t)
('a', 1, 'b', 2, 3)
タプルはリストに似ているが、要素の値を変えられない、という特徴があります。
>>>  print(t[0])		# 先頭の要素を表示
'a'
>>>  print(t[1:3])		# 1番目の要素から(3-1)番目の要素までを表示
(1, 'b')
>>>  t[-1] = 'c'		# 要素を変更しようとするとエラーになる
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'tuple' object does not support item assignment
そこで、一部の要素の値を変更したいときには、新たなタプルを作る必要があります。
>>>  t2 = t[:-1]+('c',)	# 最後の要素を除くタプルtに'c'だけからなるタプルを追加
>>>  print(t2)
('a', 1, 'b', 2, 'c')
タプルを接合するには、両方共タプルでなければなりません。そのため、今の例では'c'ではなく、('c', )というタプルを用いたのです。

このタプルには色々な使い方があります。

(1) 数の多重代入
いくつかの変数に一行で同時に値を代入するには、次のようにタプルが使えます:

>>>  x = 10
>>>  a, b, c = x, x**2, x**3
>>>  print( a,b,c)
10 100 1000
(2) 変数の値の入れ替え(swap)
(1)の応用になりますが、変数の値の入れ替えを次のように一行で書くことができます:
>>>  print (x, y)
3 5
>>>  x, y = y, x
>>>  print (x, y)
5 3
(3) 関数の返り値として
これについては関数の項で解説します。

(4) 関数の可変長の引数として
これについても関数の項で解説します。


関数

関数とは何か

関数によって、役に立つプログラムに名前をつけ、 その名前を使によりプログラムを呼び出して利用することができるようになります。 これがプログラミングの中での関数働きの基本です。

関数の定義は次のように、defを用いて書かれます:。

def 関数名():
  本体プログラム
次は関数の定義の例です:
def make_haiku():
  print (u"松島や")
  print (u"ああ 松島や 松島や")
# def文の終わり
defが関数定義(definition)のためのキーワードです。ここで定義された関数名は make_haiku です。関数名として使える名前は、変数名と同じ規則に従います---つまり英文字から始まり、英字や数字、下線からなります。 使用した/使用する予定の変数と同じ名前にしてはいけませんし、Pythonのキーワードも名前として使えません。 なお、関数名の次の ( ) により、この関数は引数をとらないことが示されています。

関数定義の最初の行をヘッダー、残りの部分を本体(ボディ)といいます。ヘッダーはコロン(:)で終わること、また関数の本体はインデント(段付け)されていることが大事です。インデントのためには(使えれば)タブ、もしくはスペース(2~4個ほど)が使われ、しかも行ごとに同じ個数のタブもしくはスペースを使わないとエラーになりますので注意しましょう。

関数を定義すると、同時に同じ名前の変数ができます。その値は関数オブジェクトといいます。

>>> print (make_haiku)
<function make_haiku at 0x0000000002B1B4A8>
>>> type(make_haiku)
<type 'function'>
次はこうして定義した関数の使用例です:
>>> make_haiku()
松島や
ああ 松島や 松島や

入力を受け取る関数

プログラムに名前をつけるだけではなく、次のように、入力を取れるようにすることで、関数はもっと強力になります。

def 関数名(引数): 	# 関数の入力に対応する変数のことを仮引数(かりひきすう)と呼びます
  プログラム本体

関数名(引数)     	# 関数の呼び出し部分です。この入力に対応する値のことを
                  # 実引数(じつひきすう)と呼びます。
これを使って先の俳句を作る関数を拡張したのが次の例です:
def make_haiku(word):
  print (word, u"や")
  print (u"ああ", word, u"や", word, u"や")
# def文の終わり
この関数の使用例です:
>>> make_haiku(u"中京")
中京 や
ああ 中京 や 中京 や

課題5-1

次のプログラムを実行すると、何が表示されるのか予想し、その表示結果を答えなさい。 次に、実際に実行してみて、予想結果と合うかどうかを確かめ、その結果も報告しなさい。 予想と違った場合には、なぜ違ったのか、理由を説明しなさい。

def aisatsuHiruma(name):
  print (u"こんにちは、", name, u"さん。")
# def 文の終わり

def aisatsuYoru(name):
  print (u"こんばんは、", name, u"さん。")
# def 文の終わり

name = u"太郎"
aisatsuHiruma(name)

name = u"花子"
aisatsuHiruma(name)

name = u"太郎"
aisatsuYoru(name)

name = u"花子"
aisatsuYoru(name)

課題5-2

次のプログラムを実行すると、何が表示されるのか予想し、その表示結果を答えなさい。 次に、実際に実行してみて、予想結果と合うかどうかを確かめ、その結果も報告しなさい。 予想と違った場合には、なぜ違ったのか、理由を説明しなさい。

def aisatsuHiruma(name):
  print (u"こんにちは、",name,u"さん。")
# def 文の終わり

names = [u"名古屋", u"愛知", u"神戸", u"大阪"]

for name in names:
  aisatsuHiruma(name)
# for 文の終わり

複数の値を受け取る関数

関数は二つ以上の引数を受け取ることもできます。 複数の値を受け取る関数を定義する場合、次のように仮引数の変数名をカンマで区切って指定します。

def 関数名(変数1, 変数2, ... , 変数n):
  プログラム

この関数を呼び出して使用するときは、定義部分と同じように、実引数の値(もしくは変数名)をカンマで区切って指定する必要があります。

関数名(値1, 値2, ... , 値n)

一つ目の引数(変数1、値1)を第一引数と呼び、二つ目の引数(変数2、値2)を第二引数と呼びます。 関数が実行されると、第一引数の変数1には値1が代入され、第二引数の変数2には値2が代入されます。

出力を返す関数

以下は、1からn(この場合は100)までの総和を求めるプログラムです (注意: ここはプログラムの練習なので sum関数を使いません)。

n = 100
total = 0
for i in range(1,101):
  total = total + i
# for 
print (u"合計は", total, u"です。")

n=100 と n=1000 と n=10000 の3つの数について和を求めるには、次のように、これを繰り返し使うことでできます。

n = 100
total = 0
for i in range(1,101):
  total = total + i
# for 
print (u"合計は", total, u"です。")

n = 1000
total = 0
for i in range(1,1001):
  total = total + i
# for 
print (u"合計は", total, u"です。")

n = 10000
total = 0
for i in range(1,10001):
  total = total + i
# for 
print (u"合計は", total, u"です。")

このプログラムもやはり、足し算の部分を sowa というような名前の関数にし て使えるようにすればよいのですが、さらに次のように 入力出力 を取れるようにすると、とても強力になります。

def sowa(num):
  total = 0
  for i in range(1,num+1):
    total = total + i
  # forの終わり 
  return(total)
# defの終わり 

n = 100
print (u"合計は", sowa(n), u"です。")

n = 1000
print (u"合計は", sowa(n), u"です。")

n = 10000
print (u"合計は", sowa(n), u"です。")

入力と出力を取る関数は、次のような形で、作ることができます。 入力に対応する変数のことを引数と呼びます。 出力される値のことを戻り値とか返り値 と呼ぶこともあります。

def 関数名(引数)  # 入力に対応する値を、関数を呼び出したところから受け取ります
  プログラム本体
  return(値)      # 出力に対応する値を、関数を呼び出したところに返します
# def文の終わり

このように関数を定義しておくと、関数名(引数) をプログラムの中に書くだけで、上の sowa(num) のように、簡単に繰り返し使うことができるようになります。 このように、プログラムの中に定義した関数の名前を書いてやると、そこで関数が実行され、結果が値として得られることになります。

課題5-1

次の関数を使ったプログラムが、どのような出力を出すか、 プログラムを一歩一歩追いかけることで予測しなさい。

def nijiKansu(m):
  kekka = m * m + 3 * m + 2
  return(kekka)
# def文の終わり

n = 1
print (u"入力値が", n, u"のとき、出力値は", nijiKansu(n), u"です。")

n = 2
print (u"入力値が", n, u"のとき、出力値は", nijiKansu(n), u"です。")

n = 3
print (u"入力値が", n, u"のとき、出力値は", nijiKansu(n), u"です。")

課題5-2

次のプログラムはn=5のとき、 数nに対して階乗(n x (n-1) x ... x 3 x 2 x 1)を計算するものです。 これをヒントに、まず関数を使わずに、n=5, n=10, n=50の時の階乗を計算し、 次々に結果を出力するプログラムを作成しなさい。

n = 5
kekka = 1
for i in range(1,n+1):
  kekka = kekka * i
# for の終わり
print ("答え= ",kekka)
なお、出力結果は次のようになります: [50!の表示]
50!の結果の表示において最後に現れたLは、大きな整数であることを示す記号です.
Cのようなプログラミング言語だと、50の階乗の計算はできても、結果を整数として表示することは普通できません。しかし、Pythonなら(何も特殊なことをせずとも)このようなことができてしまいます。 これもPythonの魅力の一つです。
答え= 120
答え= 3628800
答え= 30414093201713378043612608166064768844377641568960512000000000000L

課題5-3

次に、数nに対して階乗(n x (n-1) x ... x 3 x 2 x 1)を計算する関数、 factorial(n)を作成し、それを使って、課題5-2と同様に、 n=5, n=10, n=50の時の階乗を計算し、値を出力するプログラムを作成しなさい。
できれば、forを使った関数と、再帰を使った関数の二通りを作成しなさい。

[再帰関数]

再帰関数とは、その関数の実行において、その関数を(直接、間接的に)呼び出す性質の関数のことです。 階乗計算の場合、次のように数学的に定義できます。上の数学的定義と比較してください。

0! = 1
n! = n × (n-1)!	# n ≥ 1 の場合
ここで、n ≥ 1の場合、階乗計算(n!)には(n-1)!という計算の結果を使っています。 これが再帰です。これをプログラムで書くと, 次のようになります:
def factorial(n):			# 階乗計算の関数
   if (n == 0):
      return(1)
   else:
      return(n * factorial(n-1))	# ここで再帰を使っている
# def文の終わり
ここで、再帰関数の作り方の注意をします。書き方の順番を間違えたりすると、 簡単に無限ループに陥り、止まらなくなります。再帰関数を書くポイントは、 関数定義の最初に、条件文を使って「再帰を使わずに値を返す」式を書くことです。 いまみた階乗計算の関数ではそのようになっていることを確かめてください。

再帰関数の練習問題: フィボナッチ(fibonacci)数は次のように定義されます。 これに基づいて整数n (n ≥ 0)に対するフィボナッチ数を返す関数を書いてください:

fibonacci(0) = 1
fibonacci(1) = 1
fibonacci(n) = fibonacci(n-1)+fibonacci(n-2)		# n ≥ 2 の場合

課題5-4

数を要素とするリストを入力に取り、その総和を計算し、 値を返す関数arraySumを作成しなさい。 またこれを使って、以下のようにいろいろなリストの総和を出力するプログラムを作成しなさい。

a = [3,5,2,7]
print (arraySum(a))
b = [12,24,63,11,29]
print (arraySum(b))
c = [1251,3567,9399,6241]
print (arraySum(c))
なお、出力結果の例は次です:
17       # a = [3,5,2,7] 
139      # b = [12,24,63,11,29] 
20458    # c = [1251,3567,9399,6241]  

複数の値を返す関数

時には関数の返り値として複数の値を返したい場合があります。例として、2つの引数x, yをとり、x/y(商)と x%y (剰余)とを返す関数divmodを作ることを考えましょう。つまり、次のような使い方ができるとよいとします:
>>>  quot, rem = divmod(7,3 )		# divmodは商と剰余を返す関数
>>>  print (quote, ' ', rem)
2  1
それには、次のように返り値としてタプルを返すよう関数divmod を定義すれば良いのです:
def divmod(a, b):            		# aとbの商と剰余を求める
   return (a/b, a%b)			# タプルにして返す
# defの終わり

任意の個数の引数をとる関数

任意の個数の引数をとるよう関数を作ることができます。実際、組み込み関数の多く、例えば最大の要素を返すmaxや最小の要素を返すminはそのような関数です。

それには*で始まる変数(パラメタ)を仮引数に書いておきます。 この変数には、実引数を集めたタプルが代入されます。例えば、次で定義される printall関数は任意の個数の値を取り、そのすべてを表示するものです:

def printall(*args):
   print (args)
# def文の終わり
なおこの用途のために argsという変数名を使うことが多いと言っておきましょう(argsという名前の変数を使え、という意味ではありません)。

ここで、printallの動きを確認しておきましょう:

>>>  printall(1, 2.0, '3')
(1, 2.0, '3')
これとは逆に、タプルの要素をばらばらにして関数の引数に渡すのにも、*を使うことができます。前節で定義した divmod を例にしてこれを示しましょう:
>>>  t = (7, 3)			# タプルを作る
>>>  divmod(t)			# divmodの実引数にタプルを与えると...
Traceback (most recent call last):
  File "", line 1, in 
TypeError: divmod() takes exactly 2 arguments (1 given)
>>>  divmod(*t)			# 今度は *t を実引数にする
(2, 1)				# 今度はちゃんと計算できました

課題5-5

組み込み関数sumは引数としてリストやタプルをとり、その要素の和を返す関数です。 しかし、これは任意の個数の引数をとることができません。 そこで、任意の個数の引数をとり、それらの和を返す関数 sumAll を作りなさい。 (注意: 課題5-3のarraySumと似ていますが、arraySumはリストを1個引数とするのに対し、 sumAllは引数の個数がいくつでもよい、というところが異なります。) 次がその実行例とします:

>>> sum((1,2,3,4,5))		# sumは引数を1個とりその和を返す---この場合はタプル
15
>>> sum([1,2,3])		# sumは引数を1個とりその和を返す---この場合はリスト
6
>>> sum(1,2,3)			# しかし、sumは任意の個数の引数をとれない
Traceback (most recent call last):
  File "", line 1, in 
TypeError: sum expected at most 2 arguments, got 3
>>>  sumAll([1,2,3]) 
6
>>>  sumAll(1,2,3,4,5)  	# sumall は任意の個数の引数をとれる
15
[ヒント]
任意の個数の引数をとるのですから、sumAllのヘッダは次のようになるでしょう:
def sumAll(*args):
またプログラムの本体は、引数の数が1個の場合とそれ以外の場合に分けて計算する、 というものになります。引数が1個の場合は args[0] に計算すべき数からなるタプル、 もしくはリストが入っています。 引数が複数個ある場合は、argsに計算すべき数のタプルが入っています。 実際の計算には sum を使ってください。

関数の中の変数名の有効範囲(スコープ)

変数名には、変数名が意味を持つ有効範囲があります。 特に、関数の内部で使われた変数名はその関数の内部でしか意味を持ちません。 その結果、定義された関数の内部と外部で同じ名前の変数を使用しても、別の変数として扱われる。ため、 同じ変数名が使われていてもお互いの間で値のやりとりは起こりません。 このような変数名の有効範囲のことを、変数のスコープ(scope)とも言います

具体的な例で見てみましょう。下の例で、関数squareの中の変数answerの値は変化しますが、その変化は関数の外のanswerの値に何の影響も与えません。

def square(num):
  answer = num * num
  print (u"関数の中のanswerの値は", answer)
  return(answer)
# def 文の終わり

answer = 0
print (u"5の二乗を求めます...")
result = square(5)    		    # 関数squareを呼び出して実行し、戻り値を代入する。
print (u"答えは",result, u"でした\n" )
print (u"今のanswerの値は", answer, u"です。"   ) # このanswerは関数squareの中のanswerとは別物
この実行結果は以下のとおりです:
5の二乗を求めます...
関数の中のanswerの値は 25
答えは 25 でした

今のanswerの値は 0 です。

このように、関数の中の変数が外の変数に影響を持たないことで、関数を作る際に、他のところで使われている変数からの余計な影響を気にせずにつくれるようになります。 このことは、特に、大きなプログラムを分担して複数の人で作成するような場合に、重要になります。

このことから、関数の中で得られた結果は、変数を使って受け渡すことはできず、returnを使って、その関数の戻り値として受け渡すことになります。

def square(num):
  answer = num * num
  print (u"関数の中のanswerの値は", answer)
  return(answer)     # 変数answerの値を戻り値として出力する。 
# def文の終わり 

answer = square(5)    		    # 関数squareを呼び出して実行し、戻り値を代入する。
print (u"答えは", answer"です。"   ) # このanswerは関数squareの中のanswerとは別物
この実行結果は以下のとおりです:
関数の中のanswerの値は25
答えは25です。

課題5-6

次の文字列の中にに何匹「しろねこ」がいるのか数えて、その数を返すプログラムをshironeko_count(str)という関数をまず作成し、それを使って数えなさい。ただし、それには 文字列に対するsplitメソッドを使うとよいでしょう。

def shironeko_count(str):
  ...#以下を作る。
  ...
# def の終わり

str = u"しろねこ みけねこ しろねこ くろねこ しろねこ みけねこ くろねこ しろねこ みけねこ"

print ("しろねこは", shironeko_count(str), u"匹います。")

結果は次のように表示しなさい。

しろねこは4匹います。
[splitメソッド]

文字列に対するsplitメソッドは、引数がない場合は空白で、引数がある場合はその引数にマッチした文字のところで、 文字列を切り分けます。 そして切り分けた文字列を要素とするリストを返します。

>>> s = 'this is a sample sentence'
>>> s.split()
['this', 'is', 'a', 'sample', 'sentence']
>>> s.split('a')
['this is ', ' s', 'mple sentence']

課題5-7

今度は、文字列とねこの種類を渡すと、そのねこの数を文字列の中から数えるneko_count(str,type)という関数を作り、それを使って、しろねこの数を数えるプログラムを作成しなさい。

def neko_count(str, type):
  #以下を作る
# def 文の終わり

str = u"しろねこ みけねこ しろねこ くろねこ しろねこ みけねこ くろねこ しろねこ みけねこ"
neko = u"しろねこ"

print (neko, u"は", neko_count(str, neko), u"匹います。")
[ヒント]

前の課題で学んだsplitメソッドを使って、リストを作ります。そして数を数える変数(初期値は0)を用意しておき、要素が値と一致するたびにその数を1ずつ増やしていきます。最後にその変数の値を返り値とすればよいでしょう。ちなみにこの例題の答は 4 となります。

課題5-8

課題5-7で作った関数neko_count(str,type)を使って、次の文字列の中から、「しろねこ」だけでなく、「くろねこ」と「みけねこ」の数も数えるプログラムを作成しなさい。

str = u"しろねこ みけねこ しろねこ くろねこ しろねこ みけねこ くろねこ しろねこ みけねこ"
しろねこは4匹います。
くろねこは2匹います。
みけねこは3匹います。

課題5-9

次のように要素が数、またはリストからなるリストがあるとします

ary = [3, 51, 2, [22, 7, 4, 8], 3, 5, [12, 13], 98]

このようなリストを引数にとり、すべての数の合計を計算するプログラムを作りなさい。

この実行結果は以下のとおりです:

228

[課題5-9のヒント]

君たちの中には、

 [3, 51, 2, [22, 7, 4, 8], 3, 5, [12, 13], 98]
において、リストの中のカッコ([ ]) を外してしまえば、
 [3, 51, 2, 22, 7, 4, 8, 3, 5, 12, 13, 98]
となるから課題5-4で作ったarraySumが使えるのでは、と思った人がいるかもしれない。

しかし、この方法は使えない。 もしも入力が "[3, 51, 2, [22, 7, 4, 8], 3, 5, [12, 13], 98]" というような「文字列」なら、文字としてのカッコを消す方法はある。 しかしこの問題の場合、カッコは「文字」ではなく「リストがそこにあることを示すマーク」 として表示されたものに過ぎない(言い換えれば、計算機の中では、文字列として表現されていない)。 だから、このような方法は使えないのである。
ここではプログラミングとしての「正攻法」について解説する。

基本は、課題5-4で作った arraySumである。 ただarraySumは要素が数の場合だけを想定し、その和を求めるものであった。
ここでは、要素が数かリストかを分けて考える必要がある。 なお、変数の値がリストか数かは、次のようにtypeを使って判定できる。

>>> ary = [1, 2, 3]			# リスト
>>> ary == type([])			# リストならTrue
True
>>> num = 234	 	      		# 数
>>> ary == type([])			# リストでないならFalse
False
なお、要素がリストの場合、arraySumを使えば、そのリストの要素の和が得られることは言うまでもないだろう。


ファイルの入出力(Input-Output)

ここではファイルについて学びます。 ファイルは、現代のコンピュータシステムの基本要素の一つです。 ワードプロセッサーや表計算ソフトのように、どんなアプリケーションプログラムでもファイルを使います。

実際、実用的なプログラムを作る上で、ファイルをプログラムの中から扱かえるようにすることは不可欠です。 ファイルから情報を読み込んで処理したり、その結果をファイルの中に書き込んだりすることが必要になります。

実は、ファイルをプログラムで扱うこと自体はそれほど難しいことではありません。 以下で、プログラムの中からファイルを扱う方法を学びましょう。

ファイルへの書き出し

次のプログラムを実行すると、コマンドプロンプトのウインドウに出力されます。
for x in range(1,4):
  if (x % 2 == 0):
     print (x, 'is an even number')		# evenは偶数
  else:
     print (x, 'is an odd number')		# oddは奇数
# for文の終わり 
1 is an odd number
2 is an even number
3 is an odd number
この結果を、ファイルにとっておくためには、少し準備が必要です。 ここで結果をとっておくファイル名を"numbers.txt"にすることにします。
まず次の命令を実行して、ファイルを扱えるようにしなければなりません。
fout = open("numbers.txt", "w")
[拡張子とファイルの名前の付け方]
例に出したファイルの名前は numbers.txt というものでした。ここでピリオドで名前が区切られていることに気をつけてください。ピリオド以降の名前(この例ではtxt)のことを「拡張子」と呼びます。Windowsではこの拡張子によって、それを扱うプログラムを関連付けしています。この例の txt は「テキストファイル」として、エディタ(秀丸エディタやTera Pad、メモ帳など)と関連付けされています。ただWindowsでフォルダを開いた時には拡張子は見えない設定になっているので気づきにくいかもしれません。ちなみにPythonのコードの拡張子は py です。また、Cプログラムのコードの拡張子は c もしくは cc でしたね。
なお、pythonでのファイルの取扱のしやすさから、ファイル名は半角の英数字だけを用いるようにしてください。

特定の名前のファイルを開いて(openして)、そのファイルを扱うための仕掛け(ファイルオブジェクトと呼びます)を、 適当な変数(上の場合はfout)に代入しておきます。 プログラムの中では、そのファイルオブジェクトに対して、書いたり読んだりする操作をしていきます。

openという命令の、ファイル名の次にある"w"は、ファイルを書き出し(Write)の形にするためのものです。 ファイル名も書き出しの"w"も、どちらも文字列で表します。 引用符(シングルクォートでもダブルクォートでもよい)を忘れないように気を付けましょう。 なお、ここでその名前のファイルがある場合には、 その中身が消去されることに注意してください。 なお、中身を消去せずに「追加書き」するものや、 ファイルから読み込みするものは後で述べます。以下がファイルを書き出しとして開くための基本形です:

fout = open("拡張子も含めたファイル名", "w")
これだけ準備しておけば、後は難しいことは、それほどたくさんはありません。
fout = open("numbers.txt", "w")
for x in range(1,4):
  if (x % 2 == 0):
     fout.write(str(x)+' is an even number\n')		# evenは偶数
  else:
     fout.write(str(x)+' is an odd number\n')		# oddは奇数
  # if文の終わり 
# for文の終わり 

fout.close()
このプログラムを実行すると、numbers.txtというファイルが作られ、前にprint文によって画面に表示された文字列が、そのファイルに書き込まれます(既にその名前のファイルがある場合は上書きされます)。 ファイルへの書き込みにはprintではなくfout.writeが使われていることに注意してください(foutのファイルオブジェクトに対してwrite命令をする、という意味)。 ここで、ファイルの書き出しにはprint命令は使えないので、print命令とwrite命令との違いについて認識しておくことが大切です。

print命令では、(1)いくつかの値を表示するにはコンマで区切れば良い、(2)数でも文字列でもそのまま書けばその値が表示される、(3)引数の間には自動的にスペースが入る、(4)文字列の表示の後に自動的に改行'\n'が入る、という特徴があります。

それに対し、write命令は(1)一つの文字列だけを引数とすることにも注意しましょう。このため、 str(x)+" is an even number\n"というように、文字列の足し算(文字列の接合)をしていたのです。(2)数を書出すには文字列にしないといけないので、この例ではstr(x)を用いている、(3)文字列同士はスペースがなく接合されるので、print命令にあわせるために、' is an ...'のように先頭にスペースをいれている、(4)最後に改行が入らないので'\n'を文字列の中に含めています。

このような違いに気をつけて fout.writeにより、変数foutの中のファイルオブジェクトに対して文字列を書き出しています。
なお、プログラムの最後にあるfout.closeという命令は、変数foutの中のファイルオブジェクトに対し、ファイルへの書き込みが終わったので、 後始末の処理(ファイルの保存など)をするためものです。 この命令を書き忘れても当面は何も困ったことは起こりませんが(プログラム終了時に自動的にcloseされます)、習慣として書くようにしましょう。 言い換えれば、ファイルは一度開けたら(openしたら)、閉めて(closeして)おいたほうがよいのです。

課題6-1

上のファイルの書き出しのプログラムを実行して、実際にnumbers.txtというファイルが作成されて、中身がどのようになっているか、エディタを使って確かめて報告しなさい。

課題6-2

上で実行したファイルへの書き出しプログラムと、その前に例として出した画面表示するプログラムを比較し、どこが違うのか、違う点を箇条書きにして報告しなさい。

ファイルへの追加書き

先の課題で、numbers.txt があるとします。ここで、 ファイルを開く(openする) ときにopen命令で"w"の代わりに、"a"としてみましょう。
fout = open("numbers.txt", "a")

for x in range(5,8):
  if (x % 2 == 0):
     fout.write(str(x)+' is an even number\n')		# evenは偶数
  else:
     fout.write(str(x)+' is an odd number\n')		# oddは奇数
  # if文の終わり 
# for文の終わり 

fout.close()
このプログラムを実行すると、すでにあるnumbers.txtというファイルの中身は消されず、 その後ろに文字列が次々と書き足されます。 これを「追加書き」(Append)といいます。

課題6-3

上のプログラムを実行し、numbers.txt ファイルの中身を確かめよ。

書式設定

メソッド write は引数が一個でないといけないと述べました。そこで、いくつかの値をファイルに書き出すには、それらを一個の文字列にしないといけないのでした。そのための簡単な方法が str を使う方法です。
>>> x = 42
>>> str(x)
'42'					# 文字列になっている
もう一つの方法は、書式設定を使う方法です。プログラミング言語Cでは printfを使って、数や文字列を表示していました。以下の例は、"10 = 5 * 2"を表示するためのCプログラミングのコードです:
// Cにおける書式設定の例
    printf("%d = %d * %d\n", 10, 5, 2);
Pythonの書式設定は、この方法に似ています。ここで使われるのは % という演算子です(この%は整数同士の場合は「剰余」を求める演算子でもありました)。今のCプログラミングのコードをこの % を使って書くと次のようになります:
# Pythonの書式設定の例
print ("%d = %d * %d\n" % (10, 5, 2))
このようにPythonの % は次の形式をとります:
  書式設定の文字列 % 引数(複数の引数がある場合はタプルにする)
そして、書式設定の中の(Cプログラミングと同様) %d が整数、%fが不動小点数、%sが文字列を表し、 対応する引数の値を書式設定の文字列に埋め込んでできる文字列が返されます。

ファイルからの読み込み

今度は、プログラムでファイルの中身を読み込む方法を学びます。
ファイルを読み込むためには、読み込む対象となるファイルが存在している必要があります。 前の課題で作ったnumbers.txtの中身を読み込むことにしましょう。 numbers.txtという名前のファイルが存在し、その中身が次のようなものであることをエディタで確認しておいてください。

1 is an odd number
2 is an even number
3 is an odd number

まず、ファイルの書き出しと同様に、ファイルを扱えるようにしなければなりません。 それには特定の名前のファイルを開いて(open)して、それを扱うための仕掛け(ファイルオブジェクト)を、 適当な変数(以下の場合はfin)に入れておき、それに対して「読む」操作をしていきます。

fin = open("numbers.txt", "r")

ちなみに、ここではファイルから文字列の「読み込み」を行うので、 右辺の括弧の中の二つ目の文字列が読み込み(Read)を指定する"r"になっています。 (書き出しの場合は"w"でした。)

この準備をしておき、readlineメソッドを使うと、ファイルの内容を1行だけ読み込みます。

fin = open("numbers.txt", "r")

line1 = fin.readline()  	# 1行目の読み込み
line2 = fin.readline()  	# 2行目の読み込み
line3 = fin.readline()  	# 3行目の読み込み

fin.close()  			# ファイルを閉じる

print (line1)
print (line2)
print (line3)
これを実行した結果、以下のような表示が得られるでしょう:
1 is an odd number

2 is an even number

3 is an odd number

readlineで読み込まれた1行分の文字列には、改行文字("\n")もついていることに注意してください。ですから、それをprintすると、このように改行が2回ずつされるのです。これが嫌な場合は、次に示すstripメソッドにより、文字列の最後の改行コードを切り落としてからprintすればよいでしょう。

>>> x = 'this is a sample sentence.\n'
>>> x.strip()
'this is a sample sentence.'			# 最後の改行コードがなくなっている
>>> print (x)
this is a sample sentence.

# 改行が2回行われた
>>> print (x.strip())
this is a sample sentence.
# 改行は1回だけ行われた
なお、numbers.txtの4行目以降何も書かれていないとすれば、もう一度readlineを呼び出すと、空文字列が返されます。

以上のことを行う別なやり方を紹介します。一つ目は read メソッドを使う方法です。 ファイルを「読み込み」で開いておき、readlineではなくreadを使うと、そのファイルの最後まで読み込み、それを一つの文字列として返します。そこで、splitを使います。

fin = open("numbers.txt", "r")			# ファイルを開く
contents = fin.read()				# ファイルの内容を読み込む
for line in contents.split('\n'):		# 改行コードで文字列を分割し、それぞれをlineにセット
   print (line)
# for文の終わり 

fin.close()

もう一つはforを使う方法です。例を見てください。

fin = open("numbers.txt", "r")			# ファイルを開く
for line in fin:				# 一行ずつ読み込みlineにセット
   print (line.strip())				# 改行コードを落としてprintする
# for文の終わり 

fin.close()
上の例ではファイルからの読み込みは、forのところで行っています。 lineにはファイルオブジェクトの内容が一行一行セットされます。 これはファイルの内容がすべて読み込まれるまで行われるのです。

課題6-4

今解説した、ファイルの内容をすべてコンピュータ画面(コマンドプロンプトのウィンドゥ)に表示する3通りの方法(readlineを用いる方法, readを用いる方法, forを用いる方法)をすべて試し、比較しなさい。

読み込み対象のファイルがあるかどうかの確認

ファイルから読み込む場合、そのファイルが実際にある場合は問題ありませんが、ファイルがない場合は。エラーが発生して、プログラムの動きが停止してしまいます。

そこで、対話的にPythonを動かしている場合は、次のようにosモジュールを用いて、実際にファイルがあるかどうか、確かめることを勧めます:

>>> import os				# osモジュールの取込み
>>> os.path.exists('test.dat')		# os.path.existsはファイルパスを引数とするブール関数
False
>>> os.listdir('.')			# os.listdir関数もパスを引数として、そこ('.'で示されている)にあるファイルのリストを返す
[ 'test.txt', 'unnamed.py']
exists関数もlistdir関数もパス(path)を引数とします。exists関数は指定されたファイルがあればTrueを、そうでなければFalseを返すブール関数です。またlistdir関数は、指定されたパスにあるファイルやディレクトリのリストをアルファベット順でソートして返します。

課題6-5

この項で説明されたosモジュールの関数 path.exists と listdirを実際に使って、その動きを確かめよ。 ただし、path.existsに対しては、実際にあるファイル名と、存在しないファイル名の2つをそれぞれ引数に与えてみよ。 また、listdir に対しては、'.' と '..' の2つをそれぞれ引数に与えてみよ。'..'ではどのようなものが表示されただろうか?

日本語の取り扱い

注意: 以下は Python2についての記述です。Python3ではunicodeが標準になりましたので、すべてがunicodeで書かれている限り、状況は改善されました。

今までに、コマンドプロンプトのウィンドゥで日本語の文字列を表示したり、日本語の文字列を読み込む方法を取り上げました。ここでは、ファイルに対して、日本語の文字列の入出力ができるかどうかを調べてみましょう。まずは入力です:

	
>>> fin = open("jpnText.txt","r")				# jpnText.txtを読み込み対象とする
>>> print( fin.readline() )					# 一行読み込む
このファイルはshift-jisで書かれています

>>> finU = open("jpnTextUnicode.txt","r")			# jpnTextUnicode.txtを読み込み対象とする
>>> print (finU.readline())					# 一行読み込む
# 文字化けする
>>> print (unicode(finU.readline(),"utf-8"))		# 一行読み込む
このファイルはutf-8で書かれています

上の例はOSがWindowsの場合です。しかしOSがLinuxやIOSでしたら状況は変わります。 ですから、文字コードは utf-8 を使うことで一貫させましょう。 つまり、私達がとるべき方法は、日本語コードとして utf-8 を採用すること--- ファイルを utf-8 でコード化する、そしてそのファイルから読み込む場合は、 unicode関数を使って変換する、という方法を基本とすることにしましょう。

次は、出力です。次の実行例をみてください:

	
>>> fout = open("test.txt","w")			# test.txtを書き込み用のファイルとして作る
>>> fout.write(u"これはテストです\n")			# 「これはテストです」を書き込む
  File "", line 1, in 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)
#  UnicodeEncodeError(ユニコード変換エラー)というエラーが発生

このように書き込みはうまく行きません。 そこで codecs というモジュールの中の open関数を使います。
>>> import codecs			# codecsモジュールを取り込む
>>> fout=codecs.open("test.txt","w","utf-8")			# test.txtをユニコードで書き込むファイルとして指定
>>> fout.write(u'これはunicodeで書き出します')
# エラーなく正常に書き込まれる
ポイントはopen関数ではなく、codecs.open関数を使うことと、その3番目の引数(コーディング方法)として"utf-8"を指定することです。ここで一つ注意をしておきます。書き込まれたファイルは utf-8を使っています。ですから、エディタではファイルの中身がみられますが、コマンドプロンプトのウィンドゥでtypeコマンドを使った場合は文字化けします。

[Shift-JISを指定して書き込む]

PCのOSであるWindows(Windows 7)がunicodeではなくShift-JISを使っている現状では、まだすべてをユニコード(utf-8)にするのは面倒かもしれません。そこでshift-jisとしてファイルに書き込む方法を紹介しておきます:
>>> import codecs			# codecsモジュールを取り込む
>>> fout=codecs.open("test.txt","w","shift-jis")			# test.txtをshift-jisで書き込むファイルとして指定
>>> fout.write(u'これはshift-jisで書き出します')
# エラーなく正常に書き込まれる
ユニコードで書き込む場合とほぼ同様です。違いは、ファイルに書き込むコーディングとして shift-jisを指定することと、書き込まれたファイルが shift-jis で表現されていることの2点です。

課題6-6

Nekos.txtというファイルの中には、いろいろな「ねこ」が文字列として入っています。このファイルの内容を読み込み、そのまま書き出すプログラムを3通りの方法で作成してください。(注意: 文字コードに注意。Nekos.txtは utf-8 で書かれている)
出力は次のようになる。
しろねこ みけねこ みけねこ しろねこ しろねこ みけねこ しろねこ しろねこ みけねこ
みけねこ しろねこ みけねこ しろねこ みけねこ みけねこ しろねこ
くろねこ くろねこ しろねこ
みけねこ みけねこ しろねこ くろねこ くろねこ しろねこ みけねこ
みけねこ しろねこ みけねこ くろねこ しろねこ みけねこ
しろねこ みけねこ
しろねこ ばけねこ
...
...省略
...
しろねこ しろねこ くろねこ しろねこ
くろねこ しろねこ
くろねこ しろねこ しろねこ
しろねこ しろねこ しろねこ みけねこ みけねこ しろねこ くろねこ
しろねこ
くろねこ みけねこ みけねこ
しろねこ みけねこ みけねこ しろねこ くろねこ しろねこ くろねこ くろねこ
くろねこ みけねこ しろねこ みけねこ みけねこ みけねこ
[3通りの方法で作成する]
わからない人は、ファイルからの読み込みの項をもう一度読んでください。
                           [文字化けの対処方法]
Nekos.txtはutf-8で書かれているのに、それを読み込んで、表示させようとすると、この項で述べたように、文字化けします。

既に述べた方法ですが、次を参考にして工夫してみてください:

>>> fin = open("Nekos.txt","r")			# Nekos.txtファイルを開く
>>> line = fin.readline()				# Nekos.txtファイルから一行読み込む
>>> print (line)				# 表示させる
# 文字化けする場合は...
>>> print (unicode(line,"utf-8"))				# unicodeに変換して表示させる
しろねこ みけねこ みけねこ しろねこ しろねこ みけねこ しろねこ しろねこ みけねこ

課題6-7

課題5-7と課題6-6で作ったプログラムを参考にして、Nekos.txtファイルの中に「とらねこ」が何匹いるのかを数えるプログラムを作成しなさい。

[ヒント1]

課題6-7では、ファイルの内容を1行ずつ読み込むプログラムを作成しました。 読み込んだ行は、次のような文字列として扱うことができます。

#1行目
"しろねこ みけねこ みけねこ しろねこ しろねこ みけねこ しろねこ しろねこ みけねこ"

#2行目
"みけねこ しろねこ みけねこ しろねこ みけねこ みけねこ しろねこ"

#3行目
...

課題6-6では読み込んだ文字列をそのまま出力していましたが、今度は「とらねこ」の数を数えなければいけません。 ねこの数を数えるのは、課題5-7のプログラムが参考になりそうですね。

[ヒント2]

ファイルから1行読み込むたびに、「とらねこ」の数を数え、合計に加算していく必要があります。

合計は最初は0匹。
while ... :  #ファイルから1行ずつ読み込む。

  「とらねこ」の数を数える。

  合計に「とらねこ」の数を加算する。
# while 

「とらねこ」の数を数える所は、課題5-7で作成した通りですので、おそらく次のような形になるでしょう。

  line = 1行分の文字列
  ねこの文字列を分割する。
  「とらねこ」は最初0匹。
  for ... : #ねこを1匹ずつチェックする。(while文を使ってもよい。)
    「とらねこ」なら1匹加算する。
  # forの終わり

このプログラムを、上の合計を数えるプログラムに組み込む必要がありますので、完成すると次のような形になるはずです。

合計は最初は0匹。
for ...:  #ファイルから1行ずつ読み込む。

  line = 1行分の文字列
  ねこの文字列を分割する。
  「とらねこ」は最初0匹。
  for ...:  #ねこを1匹ずつチェックする。(while文を使ってもよい。)
    「とらねこ」なら1加算する。
  # forの終わり 

  合計に「とらねこ」の数を加算する。
# forの終わり 

ファイルから1行ずつ読み込む繰り返しの中で、ねこを1匹ずつチェックする繰り返しを行います。 (for文の中にfor文が入ります。)

課題6-8

Nekos.txtにある、いろいろな「ねこ」を、その種類と出現数を表示するプログラムを作りなさい。その結果は次のようになるでしょう(注意:このような順に表示されるとは限りません):
しろねこ の出現数は 162
くろねこ の出現数は 129
みけねこ の出現数は 141
とらねこ の出現数は 13
... (以下略)

エラーと例外

エラーは、構文エラー、意味的エラー、そして例外の3種類があります。 文や式が構文的、意味的に正しくても、実行してみるとエラーになることがあるものです。例えば、読み込み対象のファイルが存在しない、0で割り算したなど。実行中に検知されるエラーは例外(exception)と呼ばれます。これをPythonプログラムでエラーとせずに処理することができます。その方法を「例外の処理」といいます。

Pythonでは次のようにtryと exceptを用いて例外の処理を扱えます:

try:
   エラーを起こしそうなプログラム
except:
  エラーが起こったときの処理
try文では「エラーを起こしそうなプログラム」が試されます。そこでエラーがなければ、try文を抜けて次の処理に行きます。しかしエラーが起こったなら、そこでプログラムの実行を停止し、except文の「エラーが起こったときの処理」が行われます。

このようにtry文で例外を扱うことを「例外をキャッチする(捕らえる)」といいます。例えば、次はファイルの処理において何らかのエラーが起きた時に、something went wrong.(なにかおかしい)と表示するコードの例です

try:
	fin = open('bad_file.txt')
	for lines in fin:
		print (line)
	fin.close()
except:
	print ('Something went wrong.')
# 例外処理のおわり

課題7-1

例外処理について調べなさい。それに基づき、0を含む数のリスト(例えば、[5,3,0,2])を変数xの値とし、xの要素それぞれで10を割った商を表示するプログラムを書きなさい(つまり最初は10/5, 次は10/3などを表示する)。ただし、0で割った場合でもエラーにせずに 'ouch! zero division\n' と表示すること。


クラス

Pythonはオブジェクト指向言語の一つである、と書いて理解できる人は、クラスについて分かっていることでしょう。そうでない人のために説明します。

Cでは構造体によって、構造をもつオブジェクト(言い換えれば、いくつかのパーツから構成されるモノ。例えば、計算機分野で用いられるセル、現実のオブジェクトでいえばコンピュータとか自動車のようなもの)を定義し、使うことができました。しかしそのオブジェクトに固有の関数(セルに対してはセルの値を取り出す、値を書き換える、次のセルを指すポインタを取り出す。自動車でいえば、起動する、停止する、左回転する、など)というものはないため、どの関数がそのオブジェクトに固有かどうかは、マニュアル(コメント)を見る以外に(それ用のヘッダファイルなどが整理されていない限り)方法はありませんでした。それに対し、クラスは、構造体に加えて固有の関数をセットで定義できるようにしたものとみなせます。ここでクラス固有の関数を普通の関数と区別するため「メソッド」と呼びます。

クラスを使うには、そのクラスがどのような構造を持つか、どのようなメソッドがあるかを「定義」することと、実際にその「インスタンス」オブジェクトを作って、インスタンスに値を与えたり、メソッドを適用したりすることの2つがあります。クラス定義とインスタンスとの関係は、いわば鯛焼きの金型(形を決める)と、金型に材料を加えて焼いてできる実際に食べられる鯛焼きの関係に当たります。金型一つから、材料を与えることでいろいろな鯛焼きができるのです。

クラスの定義のもっとも簡単な形を示します:

class  クラス名:
  文1 ; ... 文n
  def __init__(self, x1, ..., xk):
    文i1
     ... 
    文1m
  def メソッド2(self, y1,..., ym):
    文21
     ... 
    文2m
  ...
ここで文1 ; ... 文nや 文i1 ... 文imなどはなくてもよい。また__init__メソッドのself以外の引数x1 ... xkもなくても構いません。具体的にクラス定義について、複素数のクラス定義を例にして説明します (注: Pythonは複素数も「数」として扱えますが、ここではそれとは別にクラスの例として複素数を扱います)
class Complex: 				# 複素数クラス
      def __init__(self, real, imag):
        self.r = real
        self.i = imag
# class文の終わり
このクラス定義を用いて、複素数のインスタンス 2.0+3.0i は次のように作られます:
>>> x = Complex(2.0, 3.0)
これによりComplexクラスのインスタンスが作られ、変数xの値となります。 このインスタンスはメソッド__init__により、rとiというパーツ、正式な名称では「データ属性」を持たされ、それぞれインスタンス作成の時の引数2.0と3.0が値となっています。このことは次のように確かめることができます:
>>> x
<__main__.Complex instance at 0x0000000003E4A7C8>
>>> type(x)
instance
>>> x.r, x.i
(2.0, 3.0)
 ただこのままでは複素数の性質をもっているとは言えません。 複素数としての足し算も、掛け算も、割り算もできないからです。 そこで次のように複素数固有の関数、つまりメソッドを付け加えてみましょう。 以下で見るように、メソッドはクラス定義の中に書き込む必要があります:
class Complex: 				# 複素数クラス

  def __init__(self, real, imag):
     self.r = real
     self.i = imag
  def add(self, comp):
     real = self.r + comp.r
     img = self.i + comp.i
     return Complex(real,imag)
  def mult(self, comp):
     real = self.r * comp.r + self.i * comp.i
     imag = self.r * comp.i + self.i * comp.r
     return Complex(real,imag)
# class文の終わり# class文の終わり
これにより、次の結果が得られます (注意:このメソッドは新たな複素数を作って返すものです):
>>> x = Complex(2.0,3.0)
>>> y = Complex(-1.0, -1.0)
>>> z = x.add(y)
>>> z.r, z.i
(1.0, 2.0)
>>> z=x.mult(y)
>>> z.r, z.i
(1.0, -5.0)

課題8-1

この複素数クラスに引き算(subtract)メソッドと割り算(div)メソッドを付け加えよ。