第4回 プログラムの材料と道具#


Open In Colab


この授業で学ぶこと#

第3回では、数値や文字列といった基本的なデータの扱い方を学んだ。 プログラミングを工作に例えると、これらデータは材料にあたる。 一方で、工作における道具にあたるものが関数やメソッドである。 今回はデータについてさらに詳しく学び、関数やメソッドについても学ぶ。

データと関数#

Pythonには数値や文字列の他にもいろいろな種類のデータがある。こうした種類の違いのことをデータのtype)と言う。 データ型には、整数型int)、浮動小数点数型float)、文字列型str)、リスト型list)、ブール型bool)などがある。

データ型を調べるには type() という関数を使う。関数とは何かについて説明する前に、まずは使ってみよう。

type(3)
type(3.14)
type("text")

上から順に 3 は整数型、3.14 は浮動小数点数型、"text" は文字列型という結果になった。

ここで使った type() は、データを受け取り、そのデータ型を調べて結果を返した。 このようにデータを受け取って、何らかの処理を行った上で、必要に応じて結果を返すものを関数という。 関数は引数という変数を通じてデータを受け取り、必要に応じて戻り値を返す。 例えば type("text") というコードでは、type() 関数は "text" というデータを引数として受け取り、str という型を戻り値として返している。

関数によっては引数を複数持つこともあり、その場合はデータを , で区切って渡す。関数の使い方を一般的な形で図に表すと、次のようになる。

_images/func.png

Fig. 3 関数の使い方#

実は前回の講義でも説明なしに print() という関数を使っていた。print() は複数のデータを受け取り、戻り値を返さない関数である。

print("text1", "text2", 3)

複数のデータを渡すと、空白を間に挟んで出力する。少し細かい話になるが、この出力は print() 関数の戻り値ではなく、出力するという処理を行ったと考えるのが正しい。以下のコードを通じて、type() 関数と print() 関数の挙動の違いを比較してみよう。

a = type("text")
b = print("text")

これまで見てきたように、ノートブックにはセルの最終行の式の値を自動的に表示する機能がある。しかし、a = type("text") のような代入文は式ではないので、実行しても何も表示されない。一方で b = print("text") を実行して「text」と表示されるのは、ノートブックではなく print() 関数の機能によるものである。

a
b

また type("text")str という戻り値を返すので、a には str が代入される。一方、print("text") は戻り値を返さないので、b には何も代入されない。

printに関してよく見かけるエラー

授業中、誤って print = という代入文を実行してしまうケースをよく見かける。 そうすると print は本来の意味ではなくなってしまうので、その先 print() を使用するたびにエラーが発生する。 これを直すには、ノートブック上方のメニューバーから「ランタイム」 > 「セッションを再起動」を選択して、設定を初期化する必要がある。

整数型と浮動小数点数型#

それでは先ほど紹介したデータ型を順に見ていこう(ただし、ブール型については次回、条件分岐と合わせて学ぶ)。まず整数型(int)は、名前のとおり整数を表すデータ型である。一方、浮動小数点数型(float)は、小数を一定の精度で表現したものである。

例えば、3 は整数型のデータとして扱われるが、3.0 は浮動小数点数型のデータとして扱われる。以後、例えば整数型のデータのことを単に整数と表記することにする。

type(3)
type(3.0)

浮動小数点数が、小数を完璧な精度で表現していないという点は重要である。これは第2回の講義で説明したとおり、小数も内部では2進数で表現されており、例えば 1/3 = 0.3333... のように無限に桁の続く小数を、有限のビット数では正確に表現できないためである。 次の結果は驚きかもしれない。

0.1 * 3

わずかな差ではあるが、0.1 * 3 はなんと 0.3 にならない。 これは内部の小数の表現方法に起因する誤差によるものである。 このように小数の計算では、わずかな誤差が生じうることを念頭におく必要がある。

文字列型#

文字列型(str)は、名前のとおり文字を表すデータ型である。前回学んだとおり、両端をシングルクォーテーション( ‘ )またはダブルクォーテーション( “ )で囲うと、文字列型のデータとして扱われる。

type("Hello")
type("2.0")

"2.0" は文字列であり、数値とは明確に区別される。

3 + "2.0"

エラーメッセージにある通り、整数と文字列を足すことはできない。 この計算をエラーなく実行するためには、両者のデータ型を揃えることが必要である。 文字列を数値に変換するには int() または float() 関数を、数値を文字列に変換するには str() 関数を用いる。 結果を予想しながら、次のコードを実行してみよう。

3 + float("2.0")
str(3) + "2.0"

リスト型#

リスト型(list)は、複数のデータをまとめるためのデータ型である。データを , で区切り、両端を [] で囲うことで定義する。

x = [1, 2, 3, "four", 5.6]
type(x)

リストの各要素にはインデックスと呼ばれる整数を使ってアクセスする。 左から読むか、右から読むかに応じて2種類のアクセス方法がある。 次の図に各要素とインデックスの関係を表す。

_images/index.png

Fig. 4 インデックス#

例えば "four" という要素には次のようにアクセスすることができる。

x[3]
x[-2]

基本的には左読みのインデックスが使われる。一方、右端の要素にアクセスするときなど、右から数えるのが自然な場合には右読みのインデックスが使われる。 左読みのインデックスは、0始まりであることに気をつけよう。

リストの要素数は len() 関数により調べることができる。

len(x)

存在しない要素を指定するとエラーになる。

x[5]

練習1
リスト x が与えられるとき、その先頭(左端)の要素を print するコードを作成しなさい[1]

# xの一例
x = [5, 4, 3]

# 以下にコードを作成し、以下の部分のみ提出する

問題の趣旨

上の問題は、どのような x が与えられても、指示された要素を出力するプログラムを作成しなさいという意味である。例えば、x = [5, 4, 3] の場合に限れば print(5) は正しい出力になるが、これは問題の答えとしては正しくない。

採点は以下のように行う。下図のように(外から与えられる変数)が何パターンか用意されており、それぞれ解答と結合して実行される。全ての場合について、正しく出力されれば正解となり、1つでも上手くいかない場合があれば不正解となる。例えば、上の問題であれば x = [5, 4, 3]x = [-1, -2, -3]x = [3] の3パターンが用意されているので、それぞれの場合に 5-13 と出力されれば正解となる。

_images/answer.png

Fig. 5 解答欄#

練習2
リスト x が与えられるとき、その末尾(右端)の要素を print するコードを作成しなさい。

# xの一例 (この例では3と出力するのが正しい)
x = [5, 4, 3]

# 以下にコードを作成し、以下の部分のみ提出する

オブジェクトとメソッド#

関数の中には、それぞれのデータ型に専属の関数も存在する。そのような関数のことをメソッドという。関数とは異なり、メソッドはデータの後ろに .メソッド名() とつなげて使用する。メソッドの使い方を一般的な形で図に表すと、次のようになる。

_images/method.png

Fig. 6 メソッドの使い方#

例として、文字列型のメソッドである split() を見てみよう。split() は引数に渡した区切り文字をもとに、文字列を区切ってリストとして返す。

s = "Hello, world!"
s.split(",")
s = "Mon Tue Wed Thu Fri Sat Sun"
s.split(" ")

メソッドの場合、データ自身は引数に書かなくても自動的にメソッドに渡される。

文字列型のメソッドの他の例として upper()lower() がある。文字列をそれぞれ大文字と小文字に変換して返すメソッドであり、引数は取らない。引数は取らなくてもデータ自身はメソッドに渡されるため、実質的に引数が1つの関数を実行するようなものである。

s = "Mon Tue Wed Thu Fri Sat Sun"
s.upper()
s = "Mon Tue Wed Thu Fri Sat Sun"
s.lower()

リスト型のメソッドの例も挙げておこう。index() メソッドは、引数に渡した値がリストに含まれていれば、その(左読みの)インデックスを返す。含まれていないとエラーになる。

x = [8, 1, 3, 7, 5]
x.index(3)
x.index(7)
x.index(2)

さて、データとそれの持つメソッドをまとめたものをオブジェクトという。オブジェクトは日本語では物という意味である。Pythonに出てくるほとんど全ての要素はオブジェクトとして作られており、これまで学んできたデータも全てオブジェクトである。オブジェクトの設計図をクラスと呼び、クラスに基づいて作られる具体的なオブジェクトをインスタンスと呼ぶ。オブジェクトとインスタンスは似ているが、前者はより一般的な概念で、後者は特定のクラスを具体化したものを指す。

ここまでに出てきた概念について、理解を深めるために工作の例え話で説明してみよう。 例えば、木材を加工する状況を考える。 一言に木材といっても、重さや手触りなど1つ1つの木材には個性がある。 今、手にしている木材は、木材という概念を具体化したものであり、木材という概念がクラス、具体化したものがインスタンスにあたる。

木材を加工するときには、例えば木材用のノコギリを使って切ることになるだろう。このノコギリを使って切るという行為は、木材ならば個性に関係なく適用することができるため、メソッドと捉えることができる。 これは木材に特化したメソッドであり、ガラスなど他の物質に適用することはできない。

文字列型について、今の例え話に沿って説明してみよう。文字列 "mikan" および "banana" は異なる値(個性)を持ち、それぞれ文字列クラスのインスタンスである。どちらも文字列に専属の split() メソッドを適用できるが、その結果は値に応じて異なる。

"mikan".split("a")
"banana".split("a")

split() は文字列のメソッドであるから、他のクラスのインスタンスには適用できない。

212.split(1)

練習3
英字からなる文字列 x が与えられるとき、すべての文字を小文字に変換して print するコードを作成しなさい。

# x の一例 (この例では"hello"と出力するのが正しい)
x = "Hello"

# 以下にコードを作成し、以下の部分のみ提出する

練習4
リスト values と、その中の要素 v を与える。vvalues におけるインデックスを print するコードを作成しなさい。

# values と v の一例 (この例では3と出力するのが正しい)
values = [5, 4, 3, 2, 1]
v = 2 

# 以下にコードを作成し、以下の部分のみ提出する

練習5
リスト values と、その中の要素 v を与える。vvalues の左から何番目の要素かを print するコードを作成しなさい。

# 以下は values と v の一例 (この例では4と出力するのが正しい)
values = [5, 4, 3, 2, 1]
v = 2 

# 以下にコードを作成し、以下の部分のみ提出する