リストとタプル

このノートブックでは,一つの変数の中に複数の値を格納する方法を学びます。これ自体プログラミングで最も強力な考え方の一つですが,同様に重要な概念であるループなども出てきます。この節が理解できれば,面白いプログラムを書き始めることができ,プログラマとして全般的な力量を形成していけそうだという自信がつくはずです。

リスト

リストとは

リストは要素のコレクションで,変数に格納されるものです。要素は互いに何らかの形で関係していますが,リストに何を格納できるかということに制約はありません。次のリストの簡単な例で,それぞれの要素を素早く取り出せる方法を示します。

students = ['bernice', 'aaron', 'cody']

for student in students:
    print("Hello, " + student.title() + "!")
Hello, Bernice!
Hello, Aaron!
Hello, Cody!

リストに名前をつけて定義する

リストはオブジェクトのコレクションなので,名前は複数形にするのが良いでしょう。リストの各要素がcarならリストの名前は'cars'となります。各要素がdogなら,リストは'dogs'です。この方法なら,簡単にリスト全体('dogs')とリスト中の一つの要素('dog')を示すことができます。

Pythonでは角括弧はリストを示します。リストを定義するには,リストの名前,等号,そしてリストに含めたい値を並べて角括弧で囲みます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

リスト中の一つの要素を取り出す

リストの要素はリスト中の位置で区別するのですが,位置は0から始まります。この番号付けには,いつか必ず戸惑うことでしょう。プログラマは「一つずれる」誤りをどれだけ頻繁にしているかジョークにするくらいなので,この手の誤りをしてもあまり気を悪くしないでください。

リストの最初の要素を取り出すには,リストの名前に続いて括弧内に0を入れます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

dog = dogs[0]
print(dog.title())
Border Collie

括弧の中の数字は,要素のインデックスと呼ばれています。リストは0から始まるので,要素の添字リストの位置よりもインデックスは常に1少ない値になります。2番目の要素を取り出すには,添字には1を使うことになります。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

dog = dogs[1]
print(dog.title())
Australian Cattle Dog

リストの最後の要素を取り出す

お分かりかと思いますが,リストの最後の要素を取り出すのにインデックス2が使えます。これはうまくいくのは,リストの長さがちょうど3要素であるときだけです。リストの最後の要素を取り出すには,リストの長さがどれほどであっても,-1を使うことができます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

dog = dogs[-1]
print(dog.title())
Labrador Retriever

この記法は最後から2番目,3番目などの要素にも使えます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

dog = dogs[-2]
print(dog.title())
Australian Cattle Dog

しかしながら,リストの長さよりも大きな負の値を使うことはできません。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

dog = dogs[-4]
print(dog.title())
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-33-32c58df001ad> in <module>()
      1 dogs = ['border collie', 'australian cattle dog', 'labrador retriever']
      2 
----> 3 dog = dogs[-4]
      4 print(dog.title())

IndexError: list index out of range

練習問題

初めてのリスト

  • 値'python', 'c', 'java'をリストに格納してください。それぞれの値をリスト中の位置を使って印字してください。

初めての書式設定リスト

  • 値'python', 'c', 'java'をリストに格納してください。それぞれの値に関する文をリスト中の位置を使って印字してください。
  • 文は簡単に 'A nice programming language is value.' のようなもので結構です。

自分で考えた初めてのリスト

  • リストに格納できるものを考えてください。3つか4つの要素からなるリストを作り,リスト中の一つ以上の要素を含むメッセージを印字してください。文は簡単に"One item in my list is a __." のようなもので結構です。

リストと反復

リストのすべての要素の取り出し

これはリストに関する最も重要な概念です。リストには百万もの要素を格納できますが,3行のコードで百万の要素のそれぞれについての文を書くことができます。リストを理解し,有能なプログラマになるためには,この節をよく理解するために十分時間を取ってください。

ループを使ってリストのすべての要素を取り出します。ループはコードのブロックで作用する要素がなくなるか,ある条件が満たされるまで繰り返されます。この場合は,ループはリスト中の各要素につき1回実行されます。リストに3つの要素があれば,ループは3回回ります。

すべての要素をどのようにして取り出すか例を見て,どのように動作するか理解しましょう。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

for dog in dogs:
    print(dog)
border collie
australian cattle dog
labrador retriever
既にリストを作る方法を学んでいるので,最後の2行がどのように動作するのか理解してみましょう。 for dog in dogs: - キーワード "for" はPythonにループを使う準備をするように伝えています。 - 変数 "dog" は "s" なしで,一時的な受け皿となる変数です。この変数にPythonはリストの各要素を一度に一つずつ格納します。 - ループの初回,"dog" の値は 'border collie'です。 - ループの2回目,"dog" の値は 'australian cattle dog' になります。 - ループの3回目,"dog" の値は 'labrador retriever' になります。 - この後にはリストに要素がないので,ループは終わります。

ウェブサイトpythontutor.com では,Pythonのコード一度に1行ずつ実行できます。コードを実行させるとスクリーンに変数の値が可視化され,"dog" が持つ値がループが進むにつれて変わっていきます。またコード上を動く矢印があり,これを見ると1回だけ実行される行と何度も繰り返し実行される行があることがわかります。プログラムの動作を確認するには,Fowardボタンをクリックして可視化とスクリーンに印字される出力を見てみましょう。このような道具は,Pythonが自分のコードをどのように動かすかを理解するためのに非常に価値があります。

それそれの要素に対するさらなる操作

ループの中で値 "dog" に対してどのような操作も可能です。ここでは単に犬の名前を印字しています。

print(dog)

できることは,単に犬の単語を印字するだけに止まりません。この値に対していかようにもでき,その操作はリスト中の各々の要素に対して適用されます。リスト中のそれぞれの犬について何か述べてみましょう。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

for dog in dogs:
print('I like ' + dog + 's.')
I like border collies.
I like australian cattle dogs.
I like labrador retrievers.
これをpythontutorで可視化する。

ループの内と外

Pythonはインデントを使って何がループの内側で何が外側かを判断しています。ループの内側のコードはリストの各要素に対して実行されます。ループの後に現れる,インデントされていないコードは普通のコードと同様に1回だけ実行されます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

for dog in dogs:
    print('I like ' + dog + 's.')
print('No, I really really like ' + dog +'s!\n')
print("\nThat's just how I feel about dogs.")
I like border collies.
No, I really really like border collies!

I like australian cattle dogs.
No, I really really like australian cattle dogs!

I like labrador retrievers.
No, I really really like labrador retrievers!


That's just how I feel about dogs.
最後の行は,ループが終わった後に1度だけ実行されることに注意してください。また開業("\n")を使って,読みやすくしていることにも目を向けてください。pythontutorでコードを実行

リストの要素に番号をつける

リストをたどる場合,現在の要素のインデックスが必要になることがあります。list.index(value) という記法でも良いのですが,もっと簡単な方法があります。enumerate() 関数はリストをたどっていくと各要素のインデックスを追いかけていきます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

print("Results for the dog show are as follows:\n")
for index, dog in enumerate(dogs):
    place = str(index)
    print("Place: " + place + " Dog: " + dog.title())
Results for the dog show are as follows:

Place: 0 Dog: Border Collie
Place: 1 Dog: Australian Cattle Dog
Place: 2 Dog: Labrador Retriever

リストの要素に番号をつけるには, index 変数を用意して現在のインデックスを格納します。つまり

for dog in dogs:

の代わりに

for index, dog in enumerate(dogs)

変数 index の値は常に整数です。文字列中で印字するときは,整数を文字列に変換する必要があります。

str(index)

インデックスは常に0から始まるので,この例では place の値は現在のインデックス足す1になります。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

print("Results for the dog show are as follows:\n")
for index, dog in enumerate(dogs):
place = str(index + 1)
print("Place: " + place + " Dog: " + dog.title())
Results for the dog show are as follows:

Place: 1 Dog: Border Collie
Place: 2 Dog: Australian Cattle Dog
Place: 3 Dog: Labrador Retriever

ループでありがちな過ち ループに関してよくある過ちは,単数変数 dog ではなく,誤ってリスト全体の変数を使ってしまうというものです。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

for dog in dogs:
print(dogs)
['border collie', 'australian cattle dog', 'labrador retriever']
['border collie', 'australian cattle dog', 'labrador retriever']
['border collie', 'australian cattle dog', 'labrador retriever']

この例では,リスト中の犬それぞれを印字する代わりに,リスト全体がループを回るたびに印字されています。Pythonは個々の要素を変数 dog に格納していますが,この変数は使われていません。このようなことをしようとするとエラーが発生する場合もあります。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

for dog in dogs:
print('I like ' + dogs + 's.')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-20-8e7acc74d7a9> in <module>()
      2 
      3 for dog in dogs:
----> 4     print('I like ' + dogs + 's.')

TypeError: Can't convert 'list' object to str implicitly

練習問題

初めてのリスト(ループ版)

  • 初めてのリスト をもう一度やってみましょう。ただし今回はループを使ってリストの各々の値を印字します。

初めての書式設定リスト(ループ版)

  • 初めての書式設定リスト をもう一度やってみましょう。ただし今回はループを使って文を印字します。リスト中の全ての値に対して同じ文を書いてください。ループを使って,リストの各値に対して異なる出力を生成することはできません。

初めての自分のリスト(ループ版)

  • 初めての自分のリスト をもう一度やってみましょう。ただし今回はループを使ってリスト中の各要素に対して自分のメッセージを印字してください。ここでも,リストの各要素に対してメッセージが異なる場合は,メッセージを一つ決めてリストの各要素に対して繰り返し使ってください。

よく使うリストの操作

リストの要素を変更する

リスト中のどの要素の値でも,位置が分かれば,変更することができます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

dogs[0] = 'australian shepherd'
print(dogs)
['australian shepherd', 'australian cattle dog', 'labrador retriever']

リスト中の要素を探す

リスト中の要素の位置を探すには,index()関数を使います。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

print(dogs.index('australian cattle dog'))
1

このメソッドがValueErrorを返すときはリスト中に要求された要素がないことを示しています。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

print(dogs.index('poodle'))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-13-a9e05e37e8df> in <module>()
      1 dogs = ['border collie', 'australian cattle dog', 'labrador retriever']
      2 
----> 3 print(dogs.index('poodle'))

ValueError: 'poodle' is not in list

リストに要素が存在するか調べる

要素がリスト中に存在するか試すには,in キーワードを使います。これが役に立つのは,if-else文の使い方を学んだ後です。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']

print('australian cattle dog' in dogs)
print('poodle' in dogs)
True
False

リストに要素を追加する

リストの末尾に要素を追加する

要素をリストに追加するには,append() メソッドを使います。このメソッドは,新しい要素をリストの末尾に追加します。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']
dogs.append('poodle')

for dog in dogs:
    print(dog.title() + "s are cool.")
Border Collies are cool.
Australian Cattle Dogs are cool.
Labrador Retrievers are cool.
Poodles are cool.

<!--

Inserting items into a list

We can also insert items anywhere we want in a list, using the insert() function. We specify the position we want the item to have, and everything from that point on is shifted one position to the right. In other words, the index of every item after the new item is increased by one. -->

リストに要素を挿入する

要素はリストの任意の場所に挿入するには insert() 関数を用います。位置を指定して要素を挿入すると,それより後の要素は一つ右にずれます。すなわち新しい要素より後の全ての要素のインデックスは一つ増えます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']
dogs.insert(1, 'poodle')

print(dogs)
['border collie', 'poodle', 'australian cattle dog', 'labrador retriever']

順序に注意しましょう。新しい要素の位置を先に,新しい要素の値をその次に与えます。逆にするとエラーが出ます。

空のリストを作る

成された後に要素を追加する方法を学びましたので,リストをより動的に使うことができます。リスト全体を一度に作成することにもう縛られません。

リストでよく使われる方法は,空のリストを作りプログラムを使って必要に応じて要素をリストに追加すると言うものです。この方法は,例えば対話的なウェブサイトを構築し始めるるときに使えます。最初はユーザのリストは空ですが,サイトにユーザが登録すると長くなっていきます。ウェブサイトの動作を簡略化したものですが,この考え方は現実的です。

次の短い例では,空のリストをどのように作り,埋め始めるのか,要素をどのように操作するのかを示しています。ここで新しいことは空のリストを作る方法ですが,単に空の角括弧の組です。

# Create an empty list to hold our users.
usernames = []

# Add some users.
usernames.append('bernice')
usernames.append('cody')
usernames.append('aaron')

# Greet all of our users.
for username in usernames:
    print("Welcome, " + username.title() + '!')
Welcome, Bernice!
Welcome, Cody!
Welcome, Aaron!

リスト中の順序を変更しなければ,リストを使って一番古いユーザと新しいユーザを調べることができます。

# Create an empty list to hold our users.
usernames = []

# Add some users.
usernames.append('bernice')
usernames.append('cody')
usernames.append('aaron')

# Greet all of our users.
for username in usernames:
print("Welcome, " + username.title() + '!')
# Recognize our first user, and welcome our newest user. print("\nThank you for being our very first user, " + usernames[0].title() + '!') print("And a warm welcome to our newest user, " + usernames[-1].title() + '!')
Welcome, Bernice!
Welcome, Cody!
Welcome, Aaron!

Thank you for being our very first user, Bernice!
And a warm welcome to our newest user, Aaron!

一番新しいユーザを歓迎するコードは,インデックス-1を使っているのでずっと正しく動作します。インデックス2を使っていたら3番目のユーザになりますが,ユーザのリストがどんどん大きくなってもずっとそのままです。

リストをソートする

リストをアルファベット順にソートする(並べ変える)ことができます。正順にも逆順にもできます。

students = ['bernice', 'aaron', 'cody']

# Put students in alphabetical order.
students.sort()

# Display the list in its current order.
print("Our students are currently in alphabetical order.")
for student in students:
    print(student.title())

#Put students in reverse alphabetical order.
students.sort(reverse=True)

# Display the list in its current order.
print("\nOur students are now in reverse alphabetical order.")
for student in students:
    print(student.title())
Our students are currently in alphabetical order.
Aaron
Bernice
Cody

Our students are now in reverse alphabetical order.
Cody
Bernice
Aaron

sorted()sort() の比較

リストをソートするときは,元の順序に戻すことはできないことを覚えておきましょう。ソートした順にリストを表示したいが元の順序をとっておきたいときは,sorted() 関数が使えます。sorted() 関数にも随意な引数 reverse=True を与えることができます。

students = ['bernice', 'aaron', 'cody']

# Display students in alphabetical order, but keep the original order.
print("Here is the list in alphabetical order:")
for student in sorted(students):
    print(student.title())

# Display students in reverse alphabetical order, but keep the original order.
print("\nHere is the list in reverse alphabetical order:")
for student in sorted(students, reverse=True):
    print(student.title())

print("\nHere is the list in its original order:")
# Show that the list is still in its original order.
for student in students:
    print(student.title())
Here is the list in alphabetical order:
Aaron
Bernice
Cody

Here is the list in reverse alphabetical order:
Cody
Bernice
Aaron

Here is the list in its original order:
Bernice
Aaron
Cody

リストを逆順にする

これまでリストの順序は3種類登場しました。

  • 作られた元の順序
  • アルファベット順
  • 逆アルファベット順

使える順序はもう一つあり,リストの元の順序の逆です。reverse() 関数を使うと得られます。

students = ['bernice', 'aaron', 'cody']
students.reverse()

print(students)
['cody', 'aaron', 'bernice']

逆にすると順序が変わってしまいますが,reverse() を引き続きもう一度適用すればリストの元の順序が復元できます。

数値リストの並べ替え

全てのソート関数は数値リストに対しても使えます。

numbers = [1, 3, 4, 2]

# sort() puts numbers in increasing order.
numbers.sort()
print(numbers)

# sort(reverse=True) puts numbers in decreasing order.
numbers.sort(reverse=True)
print(numbers)
[1, 2, 3, 4]
[4, 3, 2, 1]
numbers = [1, 3, 4, 2]

# sorted() preserves the original order of the list:
print(sorted(numbers))
print(numbers)
[1, 2, 3, 4]
[1, 3, 4, 2]
numbers = [1, 3, 4, 2]

# The reverse() function also works for numerical lists.
numbers.reverse()
print(numbers)
[2, 4, 3, 1]

リストの長さを調べる

リストの長さを調べるには len() 関数を使います。

usernames = ['bernice', 'cody', 'aaron']
user_count = len(usernames)

print(user_count)
3

リストにいくつの要素があるか知りたいということはよくあります。ユーザを格納したリストがあれば,いつでもリストの長さを調べてユーザが何人か知ることが可能です。

# Create an empty list to hold our users.
usernames = []

# Add some users, and report on how many users we have.
usernames.append('bernice')
user_count = len(usernames)

print("We have " + str(user_count) + " user!")

usernames.append('cody')
usernames.append('aaron')
user_count = len(usernames)

print("We have " + str(user_count) + " users!")
We have 1 user!
We have 3 users!

Pythonの文法では,len() 関数は整数を返すので,直接文字列とともに印字することはできません。関数は整数を文字列に変える str() を使うとうまく印字できます。

usernames = ['bernice', 'cody', 'aaron']
user_count = len(usernames)

print("This will cause an error: " + user_count)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-43-92e732ef190e> in <module>()
      2 user_count = len(usernames)
      3 
----> 4 print("This will cause an error: " + user_count)

TypeError: Can't convert 'int' object to str implicitly
usernames = ['bernice', 'cody', 'aaron']
user_count = len(usernames)

print("This will work: " + str(user_count))
This will work: 3

練習問題

仕事リスト

  • リストを作り,'programmer' や 'truck driver'のような仕事を4つ格納してください。
  • list.index() 関数を使ってリスト中の仕事のインデックスを一つ調べましょう。
  • in 関数を使ってこの仕事がリストにあるか確認しましょう。
  • append() 関数を使って新しい仕事をリストに追加してください。
  • insert() 関数を使って新しい仕事をリストの先頭に追加してください。
  • ループを使ってリストに含まれる全ての仕事を表示してください。

空から始める

  • 仕事リスト でできたリストを作りますが,今度はからのリストから初めて append() 文を使ってリストを埋めていってください。
  • 最初の仕事が何か示す文を印字してください。
  • 最後の仕事が何か示す文を印字してください。

順序付き仕事リスト

  • 仕事リストで作ったリストを使います。
  • リストを色々な順序で印字します。
  • リストを印字するときは,リストそのものの印字ではなくループを使ってください。
  • どの順序でリストを表示したのかを示すメッセージを印字してください。
    • リストをを元の順序で印字してください。
    • リストをアルファベット順に印字してください。
    • リストをを元の順序で印字してください。
    • リストを逆アルファベット順に印字してください。
    • リストを元の順序で印字してください。
    • リストをを元の順序とは逆順で印字してください
    • リストを元の順序で印字してください。
    • リストをを永続的にアルファベット順にソートして,印字してください。
    • リストを永続的に逆アルファベット順でソートして,印字してください。

順序付き数値リスト

  • リストを作って,ランダムな順番で5つの数字を格納してください。
  • リストを様々な順序で印字します。
  • リストを印字する際は,forループを使い,リスト自体は使わないようにしましょう。
  • 毎回どの順序か示すメッセージを印字してください。
    • 数字を元の順序で印字してください。
    • 数字を小さい順に印字してください。
    • 数字を元の順序で印字してください。
    • 数字を大きい順で印字してください。
    • 数字を元の順序で印字してください。
    • 数字を元の順序とは逆順で印字してください。
    • 数字を元の順序で印字してください。
    • 数字を永続的に小さい順でソートして,印字してください。
    • 数字を永続的に大きい順でソートして,印字してください。

リストの長さ

  • これまでの練習問題で作った2, 3のリストをコピーするか,新しいリストをいくつか作ってください。
  • 個々のリストがどれくらいの長さか示す一連の文を印字してください。

リストから要素を削除する

おそらくこれまでにリストは動的構造であることがお分かりかと思います。空のリストを定義し,プログラムに情報が入る度にリストを埋めていくことができます。本当に動的にするには,いらなくなった要素をリストから取り除く方法が必要です。要素は位置や値を使ってリストから取り除くことができます。

位置で要素を削除する

リスト中の要素の位置が分かっていれば,その要素を del コマンドを使って削除できます。この方法を使うには del コマンドの後にリストの名前と削除したいインデックスを角括弧[]で囲んで与えます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']
# Remove the first dog from the list.
del dogs[0]

print(dogs)
['australian cattle dog', 'labrador retriever']

値で要素を削除する

リストから要素をその値で削除することもできます。そうするには,remove() 関数を使います。リストの名前の後にremoveという単語を書き削除したい要素の値を括弧()で囲んで与えます。Pythonはリストを探索し,この値を持つ最初の要素を見つけるとそれを削除します。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']
# Remove australian cattle dog from the list.
dogs.remove('australian cattle dog')

print(dogs)
['border collie', 'labrador retriever']

与えた値を持つ最初の要素だけが削除されることに注意が必要です。複数の要素に同じ値があるときは,リストにこの値の要素がいくつか残ることになります。

letters = ['a', 'b', 'c', 'a', 'b', 'c']
# Remove the letter a from the list.
letters.remove('a')

print(letters)
['b', 'c', 'a', 'b', 'c']
リストから要素をポップする ---

プログラミングには,コレクションから要素を「ポップ」するというクールな概念があります。全てのプログラミング言語には,Pythonのリストに相当する何らかのデータ構造があります。このような構造は全てキューとして使え,キューの中の要素を処理する様々な方法があります。

簡単な方法は,空のリストから初めて,リストに要素を追加していくというものです。リストの要素に対する操作をするときは,常にリストから最後の要素を取り出し,操作を行い,その要素を取り除きます。 pop() 関数はこれを容易にします。この関数は,リストから最後の要素を削除し,その要素を返すので,返り値を使うことができます。例を見ると分かりやすいかと思います。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']
last_dog = dogs.pop()

print(last_dog)
print(dogs)
labrador retriever
['border collie', 'australian cattle dog']

この例は,先入れ,後出しです。この方法を使い続けると,最初の要素が最後の要素になります。この方法を全て実装したものは後で while ループを学ぶところで説明します。

リストからどの要素でもポップできます。そうするには,ポップしたい要素のインデックスを与えます。先入れ先出しは,リストの最初の要素をポップすれば実現できます。

dogs = ['border collie', 'australian cattle dog', 'labrador retriever']
first_dog = dogs.pop(0)
print(first_dog) print(dogs)
border collie
['australian cattle dog', 'labrador retriever']

練習問題

有名人

  • リストを作成して,4人の有名人を格納してください。
  • 一度に一人ずつリストから削除しましょう。これまでに学んだ4つの方法を全て使います。
    • リストの最後の要素をポップして,最後の要素以外どれかをポップします。
    • 一つの要素を位置で,もう一つの要素を値で削除してください。
  • 有名人がもうリストに残っていないというメッセージを印字してください。それからリストを印字してからであることを示しましょう。

関数が何か知りたい?

現時点では,もうお気づきかもしれませんが,いくつかの例にある程度コードが繰り返されています。このような繰り返しは,関数の使い方を学べば消え去ります。繰り返しに嫌気がさしているなら,この節の練習問題に取り組む前に初めての関数をご覧ください。

リストのスライス

リストは要素のコレクションなので,その一部の要素を取り出せるようになっていることが望ましいのではないでしょうか。 例えば,リストから最初の3つの要素を取り出すとしたら,これは非常に簡単にできてしかるべきです。同様にリストの中間からどの3つの要素でも,最後の3つの要素でも,いくつの要素をどこからでも取り出し可能であるべきです。このようなリストの一部は スライス と呼ばれています。

リストの一部を作るには,必要な最初の要素と含めない最初の要素を与えます。スライスlist[0:3]は要素0, 1, 2を含みますが,要素3は含まれません。次に最初の3名を取り出す方法示します。

usernames = ['bernice', 'cody', 'aaron', 'ever', 'dalia']

# Grab the first three users in the list.
first_batch = usernames[0:3]

for user in first_batch:
    print(user.title())
Bernice
Cody
Aaron

リスト中のある位置まで全てを取り出す場合,最初のインデックスは省略できます。

usernames = ['bernice', 'cody', 'aaron', 'ever', 'dalia']

# Grab the first three users in the list.
first_batch = usernames[:3]
for user in first_batch: print(user.title())
Bernice
Cody
Aaron

スライスをリストから作っても,元のリストは影響を受けません。

usernames = ['bernice', 'cody', 'aaron', 'ever', 'dalia']

# Grab the first three users in the list.
first_batch = usernames[0:3]

# The original list is unaffected.
for user in usernames:
print(user.title())
Bernice
Cody
Aaron
Ever
Dalia

リストのどの部分でも,スライスを使って取り出せます。

usernames = ['bernice', 'cody', 'aaron', 'ever', 'dalia']

# Grab a batch from the middle of the list.
middle_batch = usernames[1:4]

for user in middle_batch:
    print(user.title())
Cody
Aaron
Ever

リストのある位置から最後まで全ての要素を取り出す場合,2番目のインデックスは省略できます。

usernames = ['bernice', 'cody', 'aaron', 'ever', 'dalia']

# Grab all users from the third to the end.
end_batch = usernames[2:]

for user in end_batch:
    print(user.title())
Aaron
Ever
Dalia

リストをコピーする

スライス記法を使うとリストのコピーを作成できます。始まりと終わりのインデックスとも省略すると,スライスは最初の要素から最後の要素までになり,リスト全体になります。

usernames = ['bernice', 'cody', 'aaron', 'ever', 'dalia']

# Make a copy of the list.
copied_usernames = usernames[:]
print("The full copied list:\n\t", copied_usernames)

# Remove the first two users from the copied list.
del copied_usernames[0]
del copied_usernames[0]
print("\nTwo users removed from copied list:\n\t", copied_usernames)

# The original list is unaffected.
print("\nThe original list:\n\t", usernames)
The full copied list:
	 ['bernice', 'cody', 'aaron', 'ever', 'dalia']

Two users removed from copied list:
	 ['aaron', 'ever', 'dalia']

The original list:
	 ['bernice', 'cody', 'aaron', 'ever', 'dalia']

練習問題

アルファベットのスライス

  • アルファベットの最初から10文字をリストに格納してください。
  • スライスを使って,アルファベットの最初から3字を印字してください。
  • スライスを使って,リストの中間から任意の3字を印字してください。
  • スライスを使って,リストの中間の任意の位置から終わりまでの文字を印字してください。

保護されたリスト

  • この練習の目標はリストのコピーは元のリストを保護するということを示すことです。
  • リストを作って3人の名前を格納してください。
  • スライスを使ってリスト全体のコピーを作ってください。
  • 少なくとも2つの新しい名前を新しく作成したリストのコピーに格納してください。
  • ループを使って元のリストの全ての名前を印字してください。その際,元のリストであるというメッセージもつけてください。
  • ループを使ってコピーされたリストの全ての名前を印字してください。その際,コピーされたリストであるというメッセージもつけてください。

数値リスト

数のリストは特別なものではありませんが,数値リストの処理を効率的に行うために使える関数がいくつかあります。1から10まで数のリストを作り,これを使ってリストの中の数をどのように使えるか見ていきましょう。

# Print out the first ten numbers.
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for number in numbers:
    print(number)
1
2
3
4
5
6
7
8
9
10

range() 関数

上の例は正しく動きますが,たくさんの数を扱うときには効率的ではありません。range() 関数は長い数のリストを生成する手助けしてくれます。range() を使って同じことをする方法を二つ示します。

# Print the first ten numbers.
for number in range(1,11):
    print(number)
1
2
3
4
5
6
7
8
9
10

range 関数は始まりの数と終わりの数を取ります。得られるのは全て整数で,終わりの数は含まれません。間隔 を追加して,数と数との間隔をどれくらいにするかということを range に伝えます。

# Print the first ten odd numbers.
for number in range(1,21,2):
    print(number)
1
3
5
7
9
11
13
15
17
19

生成される数をリストに格納するには,list() 関数が使えます。この関数は range

# Create a list of the first ten numbers.
numbers = list(range(1,11))
print(numbers)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

この方法は非常に強力で,1から100万までのリストを作るのは,1から10までのリストを作るのと同じくらい簡単にできます。100万個の数を印字することは意味のないことですが,100万個の要素が実際にリストにあることを示すことはできますし,最後の10個の数字を印字してリストが正しいことを確認することができます。

# Store the first million numbers in a list.
numbers = list(range(1,1000001))

# Show the length of the list:
print("The list 'numbers' has " + str(len(numbers)) + " numbers in it.")

# Show the last ten numbers:
print("\nThe last ten numbers in the list are:")
for number in numbers[-10:]:
    print(number)
The list 'numbers' has 1000000 numbers in it.

The last ten numbers in the list are:
999991
999992
999993
999994
999995
999996
999997
999998
999999
1000000

やや分かりにくい点が二つあります。式

str(len(numbers))

numbers リストの長さを取り,文字列に変換して印字ができるようにしています。

numbers[-10:]

はリストの スライス です。インデックス -1 はリストの最後の要素で,インデックス -10 はリストの末尾から10番目を示します。したがって numbers[-10:] はその要素からリストの末尾までになります。

min(), max(), sum() 関数

次の3つの関数は,数値リストに使いやすいものです。予想通り,min() 関数はリスト中の最小の数を,max() はリスト中の最大の数を,sum() はリスト中の全ての数の総和を返します。

ages = [23, 16, 14, 28, 19, 11, 38]

youngest = min(ages)
oldest = max(ages)
total_years = sum(ages)

print("Our youngest reader is " + str(youngest) + " years old.")
print("Our oldest reader is " + str(oldest) + " years old.")
print("Together, we have " + str(total_years) + " years worth of life experience.")
Our youngest reader is 11 years old.
Our oldest reader is 38 years old.
Together, we have 149 years worth of life experience.

練習問題

1から20まで

  • range() 関数を使い,1から20までの数をリストに格納し,印字してください。このプログラム first_twenty.py とします。

大きなリスト

  • 今書いた first_twenty.py から始めます。終わりの数字をもっと大きな数字に変えてみましょう,1から100万までの数字をコンピュータで印字するのにどれくらいの時間がかかるでしょうか。(ほとんどの人は,100万個の数字がスクロールしていくのを目の前で見ることはありません。今見ることができるのです!)

5つの財布

  • 5つの財布があり異なる額の現金が入っているとします。5つの値をリストに格納し,次の文を印字しましょう。
    • "一番厚い財布には $ value 入っています。"
    • "一番薄い財布には $ value 入っています。"
    • "全部で財布には $ value 入っています。"

リスト内包

この節を含めるかどうか注意深く検討しました。プログラミングが全く初めてなら,一見するとリスト内包は難しいく見えるかもしれません。リスト内包は,リストを生成し操作する際に短く表記する方法です。リスト内包について知って置くのは悪いことではないと思います。他人のコードに現れ,使い方を理解すれば本当に便利だからです。しかし,まだ理解できないなら,すぐに使わなくても構いません。今は,その存在を知り目にしたときにそれだと気づけば十分です。気に入ったら,今からでも使い始めてください。

数値内包

二乗された数を小さい方から10個のリストをどのように作るか考えてみます。次のようにできます。

# Store the first ten square numbers in a list.
# Make an empty list that will hold our square numbers.
squares = []

# Go through the first ten numbers, square them, and add them to our list.
for number in range(1,11):
    new_square = number**2
    squares.append(new_square)
    
# Show that our list is correct.
for square in squares:
    print(square)
1
4
9
16
25
36
49
64
81
100

この方法は理解できると思います。理解できない場合は,以下のことに注意して,もう一度見てみましょう。

  • squares というからのリストを作り,これに値を入れていきます。
  • range() 関数を使って,ルーブを始めて1から10まで回します。
  • ループを回る度に現在の数字を累乗して二乗を計算します。
  • 新しい値をリスト squares に加えます。
  • 新たに定義したリストをたどり,それぞれの値を印字します。

ここでこのコードを効率化します。新しい二乗を専用の変数 new_square にとって置く必要はなく,直接二乗のリストに追加すれば良いのです。

new_square = number**2

という行は取り除き次の行で二乗します。

# Store the first ten square numbers in a list.
# Make an empty list that will hold our square numbers.
squares = []

# Go through the first ten numbers, square them, and add them to our list.
for number in range(1,11):
squares.append(number**2)
# Show that our list is correct. for square in squares: print(square)
1
4
9
16
25
36
49
64
81
100

リスト内包を使うと最初の3行が1行にまとまります。次のようになります。

# Store the first ten square numbers in a list.
squares = [number**2 for number in range(1,11)]
# Show that our list is correct. for square in squares: print(square)
1
4
9
16
25
36
49
64
81
100

明らかにこのコードは前の方法よりも効率的ですが,何が起こっているのか分かりにくいかもしれません。そこで,最初の行で起こっていることを全て確認してみましょう。

squares というリストを定義します。

角括弧の中の2番目の部分に注目してください。

for number in range(1,11)

は1から10までのループを作り,それぞれの値を変数 number に格納します。ループの中で各 number に何が起こっているかは分かると思います。

number**2

それぞれの番号は累乗されて,定義したリストに格納されます。この行は次のように読むことができるでしょう。

squares = [raise number to the second power, for each number in the range 1-10] squares = [number を累乗, 1から10までの各 number について]

もう一つの例

おそらく,理解を深めるには,いくつかの例をあげてどのように内包が使われているか示した方が良いと思います。最初の10個の偶数を長い方法で作ってみましょう。

# Make an empty list that will hold the even numbers.
evens = []

# Loop through the numbers 1-10, double each one, and add it to our list.
for number in range(1,11):
    evens.append(number*2)
    
# Show that our list is correct:
for even in evens:
    print(even)
2
4
6
8
10
12
14
16
18
20

同じことをリスト内包を使ってするには,次のように考えれば良いでしょう。

evens = [multiply each number by 2, for each number in the range 1-10]
evens = [number に2をかける,1から10までの number について]

これをコードで書くと次のようになります。

# Make a list of the first ten even numbers.
evens = [number*2 for number in range(1,11)]
for even in evens: print(even)
2
4
6
8
10
12
14
16
18
20

非数値内包

数値でないリストにも内包を使うことができます。この場合,最初のリストを作ってから,内包を使って2番目のリストを最初のものから作ります。簡単な例を内包を使わずに示します。

# Consider some students.
students = ['bernice', 'aaron', 'cody']

# Let's turn them into great students.
great_students = []
for student in students:
    great_students.append(student.title() + " the great!")

# Let's greet each great student.
for great_student in great_students:
    print("Hello, " + great_student)
Hello, Bernice the great!
Hello, Aaron the great!
Hello, Cody the great!

<!-- To use a comprehension in this code, we want to write something like this:

great_students = [add 'the great' to each student, for each student in the list of students]

Here's what it looks like: --> 内包をこのコードに適用するには,次のような考え方で書きます。

great_students = [add 'the great' to each student, for each student in the list of students]
great_students = [student に 'the great' つける, students 内の各 student について]

コードは次のようになります。

# Consider some students.
students = ['bernice', 'aaron', 'cody']

# Let's turn them into great students.
great_students = [student.title() + " the great!" for student in students]
# Let's greet each great student. for great_student in great_students: print("Hello, " + great_student)
Hello, Bernice the great!
Hello, Aaron the great!
Hello, Cody the great!

練習問題

例が理解できたなら,内包を使って以下の練習問題をやってみましょう。理解できないなら,内包を使わなくても構いません。各練習問題を長い書き方でやった後に内包をどう使ったら良いか気づくかもしれません。

10の倍数

  • 10の倍数の最初10個の(10, 20, 30, ..., 90, 100)からなるリストを作ってください。やり方はいくつもありますが,リスト内包を使ってみましょう。できたリストを印字してください。

三乗

  • 二乗された数の最初の10個を作る方法を説明しました。三乗された数の最初の10個(1, 8, 27, ..., 1000)からなるリストを内包を使って作り,印字してください。

すごい!

  • 5人の名前をリストに格納してください。それぞれの名前に「はすごい!」をつけた2番目のリストをリスト内包を使って作ってください。すごいをつけたリストを印字してください。

内包をループに戻す

  • 次のコードをリスト内包を使わずに書いてください。

    plus_thirteen = [number + 13 for number in range(1,11)]

リストとしての文字列

リストにある程度慣れてきたので,文字列を見直してみます。文字列は実は文字のリストなので,リストに対する操作の多くは文字列にも適用できます。

文字のリストとしての文字列

リストと同様に文字列を for ループを使ってたどることができます。

message = "Hello!"

for letter in message:
    print(letter)
H
e
l
l
o
!

文字列からリストを生成することができます。文字列の1文字がリストの一つの要素に対応します。

message = "Hello world!"

message_list = list(message)
print(message_list)
['H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!']

文字列のスライス

リストの個々の要素と同様,文字列中のどの文字でも位置で取り出すことができます。

message = "Hello World!"
first_char = message[0]
last_char = message[-1]

print(first_char, last_char)
('H', '!')

これを拡張して文字列のスライスを作ることができます。

message = "Hello World!"
first_three = message[:3]
last_three = message[-3:]

print(first_three, last_three)
('Hel', 'ld!')

部分文字列の検索

これまで文字列についてインデックスがどのような意味を持つか見てきましたが,次に部分文字列の検索について学びましょう。部分文字列は文字列中に現れる一連の文字のことです。

in キーワードを使えば,特定の部分文字列が文字列中に現れるかどうか調べることができます。

message = "I like cats and dogs."
dog_present = 'dog' in message
print(dog_present)
True

部分文字列が文字列中のどこに現れるか調べるには,find() メソッドを使うことができます。find() メソッドは部分文字列が始まるインデックスを返します。

message = "I like cats and dogs."
dog_index = message.find('dog')
print(dog_index)
16

ただし,この関数は検索する文字列が最初に現れるインデックスだけを返します。部分文字列が一度以上含まれる場合は,それらを見逃すことになります。

message = "I like cats and dogs, but I'd much rather own a dog."
dog_index = message.find('dog') print(dog_index)
16

部分文字列が最後に現れる場所を調べるには,rfind() 関数が使えます。

message = "I like cats and dogs, but I'd much rather own a dog."
last_dog_index = message.rfind('dog')
print(last_dog_index)
48

部分文字列の置換

replace() 関数を使って任意の文字列を別の文字列に置き換えることができます。replace() 関数を使うには,置換したい文字列,それに置換して使う文字列の順で与えます。同じ文字列変数でも新しい変数でも構いませんが,新しい文字列を格納する必要があります。

message = "I like cats and dogs, but I'd much rather own a dog."
message = message.replace('dog', 'snake')
print(message)
I like cats and snakes, but I'd much rather own a snake.

部分文字列を数える

部分文字列が文字列中に何度現れるか調べるには,count() メソッドを使います。

message = "I like cats and dogs, but I'd much rather own a dog."
number_dogs = message.count('dog')
print(number_dogs)
2

文字列の分割

文字列は部分文字列の集合に分割できます。分割ができるのは,部分文字列が繰り返し現れる一つ文字で区切られているときです。文字列が簡単な(欧米語の)文からなるとき,文字列はスペースで分割できます。split() 関数は,部分文字列のリストを返します。split() 関数は引数を一つ取り,この文字で文字列を分割します。

message = "I like cats and dogs, but I'd much rather own a dog."
words = message.split(' ')
print(words)
['I', 'like', 'cats', 'and', 'dogs,', 'but', "I'd", 'much', 'rather', 'own', 'a', 'dog.']

注意すべきは,部分文字列に句読点が残っていることです。

文字列の分割でよく行われるのは,実態はリストで,コンマのような記号で区切られている文字列に対するものです。このような文字列はPythonでは扱いにくいので,リストに変換します。データをリストにすれば,もっと強力な方法で操作できます。

animals = "dog, cat, tiger, mouse, liger, bear"

# Rewrite the string as a list, and store it in the same variable
animals = animals.split(',')
print(animals)
['dog', ' cat', ' tiger', ' mouse', ' liger', ' bear']

ここではスペースが無視されていますね。split()の出力を検査し,扱うデータが考えた通りになっているか確かめておきましょう。

この方法は表計算のデータをPythonで扱うときにときに使います。多くの表計算アプリケーションはデータをコンマ区切りのテキストファイルに出力できます。このファイルを自分で書いたPythonプログラムに読んでもいいし,テキストファイルからプログラムファイルにコピー&ペーストしても良いでしょう。読み込んだ表計算データは for ループを使って処理できます。

その他の文字列メソッド

他にも文字列メソッドは多数あり,ここでは取り上げませんが必要ならドキュメントを参照してください。ほとんどのメソッドは,もう理解できることと思います。今使う必要はないかもしれませんが,文字列に対して何ができるか目を通しておくことは良いことだと思います。そうすれば特定の問題をどのように解決したら良いのかという判断力が身につくでしょう。必要となったときに,メソッド一覧を参照して,正しい文法を確認すれば十分です。

練習問題

文の一覧表示

  • 一つの文を変数に格納してください。forループを使って文から文字を一つずつ別の行に印字してください。

文をリストに

  • 一つの文を変数に格納してください。文からリストを作成してください。そのリストそのものを印字してください(ループは使わずにリストを印字します)。

文のスライス

  • 一つの文を変数に格納してください。スライスを使って最初の5文字,文の途中から任意の連続した5文字,文の最後の5文字を印字してください。

Pythonを見つける

  • 一つの文を変数に格納してください。Pythonという単語を文中で2回以上使いましょう。
  • inキーワードを使ってPythonという単語が文中に存在することを確認してください。
  • find()関数を使ってPythonという単語が文中のどこで最初に現れるか示してください。
  • rfind()関数を使ってPythonという単語が文中のどこで最後に現れるか示してください。
  • count()関数を使ってPythonという単語が文中に何回現れるか示してください。
  • split()関数を使って文を単語のリストに分けてください。リストそのものを印字してから,ループを使って行の各語を印字しましょう。
  • replace()関数を使ってPythonRubyに置換してください。

発展問題

DNAヌクレオチドの計数

  • Rosalindプロジェクトは,生命工学の概念に基づく問題集です。その目的は,プログラミングの技量が遺伝学と生物学の問題を解決するのに役立つかを示すことです。
  • 文字列に関するこの節を理解していれば,Rosalindプロジェクトの最初の問題DNAヌクレオチドの計数を解くために必要な知識があります。例題を解いてみましょう。
  • 例題に正解したら,ログインして問題の完全版に挑戦しましょう。

DNAからRNAへの転写

  • 2番目のDNAからRNAへの転写を解く知識もすでにあります。例題を解きましょう。
  • 例題に正解したら,ログインして問題の完全版に挑戦しましょう。

DNA相補鎖を作る

  • ご想像通り,3番目の問題DNA相補鎖を作るにも挑戦できます。例題がうまくいったら,完全版にも挑戦しましょう。

タプル

タプルは,要するに変化しないリストです。リストはとても動的です。要素を追加したり挿入したりすれば長くなり,要素を削除すれば短くなります。リスト中のどの要素でも変更が可能です。このようなふるまいが便利なこともありますが,誰もプログラムのどの部分もリストを変更できないようにしたいこともあります。タプルはそのような場合に使います。

技術的には,リストは変更可能(mutable)オブジェクトでタプルは変更不可(immutable)オブジェクトです。変更可能オブジェクトは変更(変化)することができ,変更不可オブジェクトを変更することはできません。

タプルの定義と要素の取り出し

タプルはリスト同様に定義できますが,角括弧の代わりに丸括弧を使います。一度タプルを作れば,個々の要素はリストのように取り出したり,forループを使ってたどることができます。

colors = ('red', 'green', 'blue')
print("The first color is: " + colors[0])

print("\nThe available colors are:")
for color in colors:
    print("- " + color)
The first color is: red

The available colors are:
- red
- green
- blue

タプルに何か追加しようとすると,エラーが出ます。

colors = ('red', 'green', 'blue')
colors.append('purple')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-37-ed1dbff53ab2> in <module>()
      1 colors = ('red', 'green', 'blue')
----> 2 colors.append('purple')

AttributeError: 'tuple' object has no attribute 'append'

同様のエラーは,タプルから要素を削除しようとしたり,要素を変更しようとしたりしたときにも発生します。一度タプルを定義したら,その値は変化することはありません。

タプルを使って文字列を作る

次の例のように,英語の文字列そのものと変数に格納した値を混ぜられるのは便利であることを学びました。

animal = 'dog'
print("I have a " + animal + ".")
I have a dog.

特に似たような文を繰り返すときに便利でした。

animals = ['dog', 'cat', 'bear']
for animal in animals:
    print("I have a " + animal + ".")
I have a dog.
I have a cat.
I have a bear.

和の記号を使う方法は,直感的なので気に入っています。いくつかの短い文字列をつないで長い文字列を作ることができるということがわかります。これは分かりやすいのですが,たくさんタイプする必要があります。もっと短く書く方法として,プレイスホルダを使ったものがあります。

Pythonは文字列の中にあるほとんどの文字をそのままにしますが,\t, \nのような例外がいくつかあります。Pythonは"%s"と"%d"を特別に扱います。これらがプレイスホルダです。Pythonが"%s"プレイスホルダを見つけると,それより先にある%記号の後の最初引数を取り込みます。

animal = 'dog'
print("I have a %s." % animal)
I have a dog.

この方法では,よりきれいに値を含む文字列を生成できます。文全体を一つの文字列で作成し,Pythonにどの値をどこに文字列に取り込むか伝えます。

animals = ['dog', 'cat', 'bear']
for animal in animals:
    print("I have a %s." % animal)
I have a dog.
I have a cat.
I have a bear.

文字列に取り込む値が複数あるときは,値をタプルにまとめる必要があります。

animals = ['dog', 'cat', 'bear']
print("I have a %s, a %s, and a %s." % (animals[0], animals[1], animals[2]))
I have a dog, a cat, and a bear.

数値の書式付き文字列

数値を文字列とともに印字するとエラーが出るのでした。

number = 23
print("My favorite number is " + number + ".")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-47-1ed2c5bb2bba> in <module>()
      1 number = 23
----> 2 print("My favorite number is " + number + ".")

TypeError: cannot concatenate 'str' and 'int' objects

Pythonは値23なのか文字列'23'なのか区別します。したがってエラーを発し,必ず数値を文字列しなければならないことを示します。数値を文字列としてキャストするためには,str()関数を使います。

number = 23
print("My favorite number is " + str(number) + ".")
My favorite number is 23.

<!--The format string "%d" takes care of this for us. Watch how clean this code is:-> 書式文字列"%d"は,この処理を引き受けてくれます。コードがどんなにきれいになるか注目してください。

number = 23
print("My favorite number is %d." % number)
My favorite number is 23.

複数の数値を使う場合,タプルにまとめるのは文字列の場合と同様です。

numbers = [7, 23, 42]
print("My favorite numbers are %d, %d, and %d." % (numbers[0], numbers[1], numbers[2]))
My favorite numbers are 7, 23, and 42.

念のため,連結を文字列の書式の代わりに使うとどれ程コードが長くなるか確認してください。

numbers = [7, 23, 42]
print("My favorite numbers are " + str(numbers[0]) + ", " + str(numbers[1]) + ", and " + str(numbers[2]) + ".")
My favorite numbers are 7, 23, and 42.

文字列と数値プレイスホルダは任意の順序で混ぜて使うことができます。

names = ['eric', 'ever']
numbers = [23, 2]
print("%s's favorite number is %d, and %s's favorite number is %d." % (names[0].title(), numbers[0], names[1].title(), numbers[1]))
Eric's favorite number is 23, and Ever's favorite number is 2.

Python 3では文字列に書式をつけるより洗練された方法がありますが,この方法よりも分かりにくいのでもう少し先にします。ここでは,連結でも書式文字列でもどちらでも良いのでどちらか決めて使って,望んだ通りの出力が得られるようにしてください。

練習問題

体操選手のスコア

  • 体操選手は,1から10までのスコアを各審判から得ます。それよりも低いあるいは高い得点はありません。全てのスコアは整数値で,各審判がつけるスコアには小数はありません。
  • 体操選手に一人の審判がつけることができるスコアをタプルに格納してください。
  • "The lowest possible score is ___, and the highest possible score is ___."という文を印字します。タプルからの値を使ってください。
  • "A judge can give a gymnast ___ points."という文を全ての点について印字してください。
    • 最初の文が"A judge can give a gymnast 1 points."となってしまいますが気にしないでください。
    • しかし,ループが正しい文法で使えたら1000点のボーナスを差し上げましょう。ヒント

タプルを用いた書き換え

  • これまでに書いた文字列の連結を使うプログラムを選んでください。
  • プログラムのファイル名の後ろに_tuple.pyをつけて保存します。例えば,gymnast_scores.pygymnast_scores_tuple.pyになります。
  • 文字列の部分を連結の代わりに%s%dを使って書き直してください。
  • 他の二つのプログラムについても同様に描き直しましょう。

コーディングスタイル: PEP 8

少し内容のあるプログラムを書き始めました。プログラムは少し長くなり,少し構造が入るようになりました。ここで,コードを書く全体的なスタイルについて考えてみまょう。

スタイル規約はなぜ必要なのか

Pythonの考案者たちは,コードは書くよりも読まれる方が多いという事実を根拠にいくつかの決定をしました。元々の開発者たちは,言語が書きやすいと同じくらい読みやすいように注意を払いました。Pythonがプログラミング言語として多くの尊敬を受けているのは,コードかとても読みやすいからです。Pythonはインデントを使ってプログラム中の行をまとめることを学びました。これによりコードの構造が読者全員に明らかになります。しかしながら,さらにプログラムを自分たちだけでなく他人にも読みやすくするためにいくつかスタイルの取り決めが必要です。

自分が書いたコードを読むであろう人たちを考えてみましょう。

半年後の自分自身

  • 最初にコードを書いたときは,何を考えていたのか分かります。しかし,再びコードを見たときに何を考えていたか簡単に思い出せるでしょうか。明日,来週,半年先では? コードは半年先にも簡単に読め,やりたいプロジェクトにすぐに戻れることが望ましいです。

共同作業をするかもしれない他のプログラマ 今日全ての大きなプロジェクトは共同作業の結果です。プログラミングを続けるなら,他の人と仕事やオープンソースのプロジェクトを共にすることなります。読みやすいコードを書き,良いコメントをつけておけば,どのような状況でも喜んであなたと仕事をしてくれるでしょう。

将来の雇用主

プログラマを雇用する人たちは大抵あなたが書いたコードを見たい,面接中に少しコードを書いて見てほしいと言うでしょう。読みやすいコードを書く習慣があれば,そのような場合でもうまくやれます。

PEPって何?

PEPはPython Enhancement Proposal(Python拡張提案)です。今のPython言語の変更を提案するとき,誰かがPEPを書きます。古いPEPの一つに,読みやすいコードを書くための指針を集めたものがあります。たくさんのことが書いてあり,今は理解できないものがあると思いますが,最初から認識しておくべき提案がいくつかあります。今から良いスタイルの習慣を身につければ,最初からきれいなコードを書くことや,自分自身でコードを理解することに役立ちます。

Pythonスタイルの基本指針

インデント

インデントにはスペースを4つ使いましょう。一定の視覚構造を作り,複数のインデント階層の確保するのに十分です。

行の長さ

  • コード1行につき79文字まで,コメントは72文字まで。このスタイル指針は,遵守する人もいれば完全に無視する人もいます。この指針は,多くのモニタの表示サイズの制限と関係しています。今日全てのモニタは1行に80文字以上表示できます。しかし仕事によく使うターミナルは,高解像度のものばかりではありません。コードを複数開いて並べておくことも多くあります。ということで,この指針は今でも多くの場合に意義があります。長い行が好みであれば,これに準じた指針として1行あたり99文字までと言うものもあります。

  • 多くのエディタには設定で鉛直の線を出して行を一定の長さに揃えることを補助することができます。Geanyでは,この設定はEdit>Preferences>Editor>Display の下にあります。"Long Line Marker"を有効にして,"Column"を79にしてください。

空行

  • 空行を使って,コードを意味のあるブロックに分割してください。これまで多くの例で見てきたと思います。長いプログラムでは2行空けることもありますが,使いすぎには気をつけましょう。

コメント

  • 行頭のシャープの後にスペース1文字空けてください。1パラグラフよりも多く書く場合は,パラグラフの間にシャープで始まる空行を入れましょう。

変数の名前の付け方

  • 変数名とプログラムのファイル名は小文字,アンダスコア,数字だけを使います。大文字を使ってもPythonは文句を言ったり,エラーを出したりしませんが,これまでに習った範囲の変数に大文字を使うと他のプログラマに誤解を与えることになります。

今はこれくらいにしておきます。この他のスタイル指針はより複雑なプログラム構造を学んだら紹介します。現時点ではこの指針に従えば,プロフェッショナルが一目置くような読みやすいコードを各方向に踏み出していると言えます。

練習問題

PEP 8を読んでみる まだしていなければ,PEP 8 - Pythonコードのスタイル指針和訳)を読んで見ましょう。Pythonを学び続ける間,度々読み返してください。コミュニティで通用している規約に従ってコードを書いていれば,有能な多くのプログラマは最初からあなたを重んじてくれるであろうことは,何度でも強調しておきたいと思います。

PEP 8を使う 長い方から3つのプログラムを選んで,各ブログラムのファイル名の末尾を_pep8.pyにしてください。コードを見直して上記のスタイル規約に合うように修正しましょう。

総合発展問題

プログラミング用語

  • リストを作って,プログラミングでこれまでに学んだ最も重要な言葉を格納してください。listのような用語を含めましょう。
  • 対応する定義のリストを作ってください。このリストを'定義'で埋めましょう。
  • ループを使って各用語とそれに対応する定義を印字しましょう。
  • このプログラムは,Pythonの辞書についての節まで取っておいてください。

ヒント

ヒントは一番下にあるので,ヒントを見ないで練習問題を解くこともできるようにしてあります。

体操選手のスコア ヒント: スライスを使いましょう。