第5回は「型と変数」の後編です。前回の記事を読まれていないかたは先にこちらをご覧ください。

文字列型

プログラミングでは、テキストデータを扱うことが非常に多いです。そのため、テキストデータを扱う「文字列型」を使いこなせるようになることが重要です。

数字はそのまま書けば認識されていましたが、文字列は「特別な記号」でテキストを囲むことではじめて、Pythonで解釈できるようになります。今まで特にことわりなくシングルクオテーション「'」を使っていましたが、それもその特別な記号のうちのひとつです。

たとえば、

text = 'abcdefg'

のように使います。

テキストも数値と同じように演算することができます。先に示したように「+」で結合もできますし、あまり知られていませんが「*」で同じ文字列を繰り返すこともできます。

>>> text = 'hello' + ' python'
>>> print(text)
hello python
>>> text = 'hello' * 3
>>> print(text)
hellohellohello

文字列をコードで作成するやりかたは以下の3つです。

シングルクオテーションで囲む

「'」という記号がシングルクオテーションです。シングルクオテーションで囲むのが、Pythonで最も一般的な文字列の宣言です。空白文字もそのまま含めることができます。

>>> text = 'hello python'
>>> print(text)
hello python

タブや改行といった特殊な文字はエスケープ処理をすることで加えることができます。たとえば改行は、"\n"と表現されます。英語キーボードの半角の\(バックスラッシュ)と日本語キーボードの¥は同じ意味なので、\n(バックスラッシュは半角)も改行の意味を持ちます。

>>> print('hello \n python')
hello 
 python

わかりやすいように\nの前後に空白をいれましたが、改行させたいだけの場合は空白は不要です。'hello\npython'と書けば改行コードが入ります。

ダブルクオテーションで囲む

ダブルクオテーションは「"」記号のことです。これで囲むとシングルクオテーションと同様に、文字列として認識されます。ほかのプログラミング言語だとダブルクオテーションのほうがよく使われるので、Pythonでもこちらを好んで使う人がいます。

シングルクオテーションとダブルクオテーションの使い分けは特に決まったものはないのですが、「シングルクオテーションをダブルクオテーションで囲むと文字として扱われる」というルールがあるので、文字列の中にシングルクオテーションを使いたい場合はダブルクオテーションを使うと便利かもしれません。

>>> print("it's nice!!")
it's nice!!
>>> print('it\'s nice!!')
it's nice!!

2つめの例のようにエスケープ記号を使うことで、シングルクオテーションの中でシングルクオテーションを使うこともできます。ダブルクオテーションでシングルクオテーションを囲むのと同じように、シングルクオテーションでダブルクオテーションを囲むこともできます。その効果はまったく同じで、ダブルクオテーションをエスケープせずに文字列で使うことができるというものです。

トリプルクオテーションで囲む

最後にトリプルクオテーションを紹介します。これはテキストをシングルクオテーションかダブルクオテーション3つで囲むというものです。トリプルクオテーションで囲まれると、その中身が見たままにテキストとして表示されます。

>>> text = '''it's nice!!'''
>>> print(text)
it's nice!!

プロンプトでは使えませんが、ファイルにプログラムを書き込む場合は、改行も含めてひとつのテキストにすることが可能です。たとえば以下をPythonのプログラムファイルに書き、

text = '''hello
python'''
print(text)

それを実行すると

hello
python

が返されます。

ちなみにトリプルクオテーションは文字列の宣言としての利用よりも、複数行のプログラムをコメントアウトするときに使われることが多いかもしれません。たとえば以下のような例があげられます。

処理1
'''
処理2-1
処理3-1
'''
処理2-2
処理3-2
処理4

処理2,3の動きを変更したいと思ったので、昔の処理「2-1,3-1」を文字列にしてしまうことで実行されないようにして、新しく「処理2-2,3-2」を書いたものです。改良やバグ探しの場面では「昔の処理は実行させたくないのだけれども、消したくはない」ということが多く発生するので、そのようなときにトリプルクオテーションが便利です。また、関数やクラスの前に「それが何をやっているか」ということをトリプルクオテーションで表明することもよくあります。

なお、CやJavaでいうところの範囲指定のコメントアウト「/** コメントアウト **/」はPythonでは使えないので注意してください。

文字列型の操作

文字列の操作については後の連載で詳細を扱いますので、ここでは簡単な説明にとどめておきます。演算子の利用は先に話したとおりです。

>>> 'hello' + 'python'
'hellopython'
>>> a = 'hello'
>>> a += 'python' 
>>> print(a)
'hellopython'

これに加えて関数を使う方法もあります。たとえば数値などの「文字列でない型」を文字列型にするにはstr関数を使います。この関数で囲ったすべての型は文字列に変換されます。

>>> str(5)
'5'
>>> str(5.5)
'5.5'

この関数は文字列に「文字列以外の型」を結合する際によく使われます。この変換をしないとエラーになる場合が多々あります。たとえば、以下の1行目の「文字列 + 数値」はエラーとなりますが、2行目は「文字列 + 文字列」なので問題ありません。

>>> 'hello' + 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
>>> 'hello' + str(5)
'hello5'

文字列に対するより複雑な操作は「文字列から関数を呼び出す」ことで行います。なぜこのような書きかたをするかについては連載後半で扱いますが、とりあえずは "文字列.関数()" とすることで文字列に対する操作をすると覚えておいてください。文字列を格納した変数に対して "変数.関数()" としても同じです。

>>> a = 'Hello Python'

# 'Py' が 'Hello Python' の前から何番目にあるか。0からカウント。
>>> a.find('Py')
6

# 'Hello Python' を小文字にする
>>> a.lower()
'hello python'

# 'Hello Python' を空白 ' ' で分割する
>>> a.split(' ')
['Hello', 'Python']

# 'Hello Python' のなかにある文字列 'Hell' を取り除く
>>> a.strip('Hell')
'o Python'

Bool型

Boolは別名「真偽値」とも呼ばれる型です。真偽値という名前を聞くとなんだか難しそうに思えるかもしれませんが、要するにYES/NOに相当する「True/False」という「正か非」の2値しかない単純な型です。

Pythonのプログラム中で "True" と "False" は特別なキーワードとして扱われます。それぞれその言葉のとおりに、YES/NOとしてPythonに解釈されるのです。このようなキーワードのことを「予約語」と呼び、予約語は変数名や関数名に使うことはできません。

Boolは「比較演算子」と呼ばれる記号で2つの値を比較した際に返されます。例として数字の大小を比較してみます。

>>> 10 > 5
True
>>> 10 < 5
False
>>> a = 10 > 5
>>> a
True

特に難しいことはありませんね。「10は5より大きい -> True(YES)」とされていますし、「10は5より小さい -> False(NO)」とされています。Boolを変数に格納することも当然できます。

比較演算子の一覧を以下に記載します。and、or、notがCやJavaと異なりますが、それ以外はほぼ同じです。

利用可能な演算子 説明
A == B AとBが同一ならTrue
A != B AとBが異なればTrue
A <> B 同上(あまり使われない)
not A AがFalseならTrue
A and B AもBもTrueならTrue
A or B AかBがTrue

以下に例を書いてみます。

>>> 'hello' == 'world'
False
>>> 'hello' != 'world'
True
>>> a = 'hello'
>>> b = 'hell' + 'o'
>>> a == b
True

>>> not True
False
>>> True and False
False
>>> True or False
True

ほかには返り値がBool値である関数もよく利用されます。Bool型は次回以降で扱う「ifやfor」といった制御文で利用されることが多いため、これもマスターが必須な型です。条件分岐のif文では、たとえば変数aがTrueなら処理Aを実行し、Falseなら処理Bをするといった使い方をします。具体的にBoolをどのように書くかは制御文を学ぶ際に理解できると思いますので、今回はここで解説を切り上げます。

リスト

リスト(List)が今回紹介する最後の型です。言葉からわかるようにデータを「リスト」状に複数個並べたような型です。今までの数値や文字列、Boolに比べると使いどころがよくわからないかもしれないので、まずは例を示します。

たとえば生徒のテストの点数を管理するアプリケーションを書くとします。リストを使わずに3人の生徒の平均点を求めようとすると、以下のようなコードが書けます。

student1 = 68
student2 = 81
student3 = 49
average = (student1 + student2 + student3) / 3
print(average)

生徒ごとに変数を作って、そこから平均値を求めています。それほど難しくはありませんね。ただ、上記のプログラムには問題があります。たとえば生徒の数が4人になった場合などに修正する箇所が多くなってしまうことです。生徒が40人だと変更はもっと大変です。

このような問題は、リストを使うことでかなり解消できます。リストは「リストというデータの中に複数のデータを格納できる」という型ですので、「生徒達の点数」というデータに「具体的な各生徒の点数」を格納します。

results = [68, 81, 49]
average = sum(results)/len(results)
print(average)

1行目では「生徒たちの点数」というリストを作成しています。見ればわかると思いますが、リストは [] の記号のなかにコンマ区切りでデータを羅列することで作成されます。2行目にあるsum()はリスト内にあるデータの合計値を算出する関数で、len()はリストに格納されるデータの数を返す関数です。ここでは平均値を求めるために「生徒の点数の合計値/生徒の人数」としています。

2番目のコードは生徒一人ひとりの点数ごとに変数を作成していないので、「複数の生徒たちの点数の格納」も簡単ですし、なにより平均値の算出方法が生徒の数に依存していません。このようにリストを使うことで「ひとつのグループに属するデータ」を便利に扱うことができます。

リストの概念を以下に記します。

リストの概念

リストの操作

リストがどのようなものかわかっていただけたかと思いますので、操作方法について例を交えながら説明していきます。リストの作成は以下のように [] 記号でリストの要素を囲むことで実現できます。

>>> a = []
>>> b = [1, 2, 3]
>>> c = [1, "2", False]

[] の中に何も入れない場合は空のリストを作成します。注意が必要なのは3行目のように「リストの中にはさまざまなデータが入れられる」ということです。基本的には同じ型しか入れられないCやJavaの配列やリストとは違うので注意してください。

次にリストの「要素」を取り出したり、書き換えたりする方法を示します。先の b = [1,2,3] では要素数が3つあるリストを作成していて、その中身は1、2、3となっています。この中身を取り出すためにはリスト内の「x番目の要素を指定」する必要があります。

そのためには、

リスト名[要素の番号]

とします。

ただ、気をつけなければいけないのは、指定する順序は1からではなく0からということです。たとえば、以下のように使います。

b = [1,2,3]
print(b[0]) # -> 1
print(b[2]) # -> 3
b[1] = 5
print(b[1]) # -> 5

ちなみに、この「x番目」ということを「インデックス番号」と呼びます。b[2]は、「リストbのインデックス番号が2の要素」という意味になります。

次にリストにデータを追加する方法です。追加するといっても「リスト末尾への追加」と「リストの途中への追加」でやりかたが異なります。これには文字列型の説明でお伝えした「変数名.関数()」という操作方法を使います。

>>> b = [1,2,3]
>>> b.append(4)   # 末尾への追加
>>> print(b)
[1, 2, 3, 4]
>>> b.insert(1,10)   # 1番目の要素に10を追加
>>> print(b)
[1, 10, 2, 3, 4]

追加とくれば削除です。削除にはremove関数を使います。

>>> b = [1,2,3]
>>> b.remove(1)
>>> print(b)
[2, 3]

ほかにもさまざまな操作がありますが、あえてひとつだけあげるのであればリスト長の取得です。リスト範囲外へのアクセスはエラーになってしまうので、リスト長を超えたアクセスをしないためにもリスト長をどうやって取得するかを知っておく必要があります。

>>> b = [1,2,3]
>>> b[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> len(b)
3

つまり、len(配列)で配列長を得て、要素へのアクセスは「配列長 - 1」番目までとすればよいのです。これら以外のリストの使い方については、まず上記をマスターしてからでよいと思いますので、解説はいったんここで終えます。

配列とリスト

このセクションではCやJavaの「配列」とPythonのリストを比較します。そのため、配列をそもそも知らない方は、飛ばしてもらってかまいません。

まず簡単に両者のイメージ図を記載します。

配列とリストのイメージ

左側の配列は「メモリ」上に連番でデータを格納するスペースを用意するのに対して、右側の「リスト」は複数のデータ間を順序を持って結びつけることで実現されています。

Pythonのリストは、CやJavaのVectorやListに相当する型です。Pythonのリストはまるで配列のように利用されますが、CやJava の配列とは大きく異なります。たとえば純粋な配列では、「要素(配列やリストの中にあるデータ。Elementとも呼ぶ)」の間に 新しいデータを挟み込むことはできません。そのため、配列に入っている要素を詰め替えるなどしてデータを追加します。

配列のデータ追加方法

一方、リストはN-1番目の要素とN番目の要素の間に新しいデータを挟み込むことができます。配列ではメモリ上に要素を連番で格納するためのスペースを用意するのに対し、リストは以下の図のようにバラバラに用意された要素間を順に結びつけることで実現されているためです。

リストのデータ追加方法

Javaの配列のコードを確認してみます。

int a[] = {0, 1, 2};
System.out.println(a[1]);      // 2番目の要素の値を取得 -> 1
System.out.println(a.length);  // a の配列長を取得 -> 3
a[1] = 10;
a[3] = 3;  // Error

1行目では要素数3のint型の配列の変数を宣言し、それに代入しています。前記事でお伝えしたように、Javaの変数には型があるのでしたね。a[x]とすると配列aのx番目の要素にアクセスできます。そして、a.lengthとすることで配列長が取得できます。

4行目では配列の2番目の要素に値を代入しています。ただ、5行目では配列長3の4番目の要素に値を代入しようとしているのでエラーとなってしまいます。

次にPythonのリストを使ってみます。Pythonの変数には型がないので、特に型を指定していない変数aに[0, 1, 2]という3要素のリストをそのまま代入しています。2行目ではリストの中身を確認しています。そして3行目では配列長を取得しています。

a = [0, 1, 2]
print(a[1])     # 2番目の要素の値を取得 -> 1
print(len(a))   # a の配列長を取得 -> 3
a[1] = 10;
a.append(3)
print(len(3))   # 4

異なるのは5行目です。配列は配列長を超えて要素を代入することができませんが、リストはリスト長を伸ばすことができます。Pythonではリストをまるで配列のように使いますが、両者はあくまでも別物という認識を持っておく必要があります。


演習1

文字列 ' hello ' から前後の空白をすべて取り除いてください。

演習2

以下の図のCとDおよび2つの円をくっつけた領域をAとBを用いて表現してください。


次回は制御構造について扱います。今回取り扱ったBoolやリストは制御構造に大きく関わるので、不安な人はもう一度資料を読み直すなどしておいてください。

執筆者紹介

伊藤裕一(ITO Yuichi)

シスコシステムズでの業務と大学での研究活動でコンピュータネットワークに6年関わる。専門はL2/L3 Switching とデータセンター関連技術およびSDN。TACとしてシスコ顧客のテクニカルサポート業務に従事。社内向けのソフトウェア関連のトレーニングおよびデータセンタとSDN関係の外部講演なども行う。

もともと仮想ネットワーク関連技術の研究開発に従事していたこともあり、ネットワークだけでなくプログラミングやLinux関連技術にも精通。Cisco社内外向けのトラブルシューティングツールの開発や、趣味で音声合成処理のアプリケーションやサービスを開発。

Cisco CCIE R&S, Red Hat Certified Engineer, Oracle Java Gold,2009年度 IPA 未踏プロジェクト採択

詳細(英語)はこちら