第5回 - for文、文字列、データの型

  1. 前回の復習
  2. プログラミングが苦手な人へ
  3. 条件式 True と break文
  4. For文
  5. 文字列
  6. データの「型」について
  7. 本日の課題

雑談

ゲームジャム (game jam) とは何か?

0. 前回の復習

演習 5-1. うるう年の判定

西暦 y 年がうるう年かどうかを判定するプログラムを作りたい。

グレゴリオ暦: “4年に1度うるう年があるが、100年に1度はない、しかし400年に1度はうるう年がある”
  1. 「変数 y が 4 で割り切れる」を表す条件式を Python で書け。
  2. 「変数 y が 4 で割り切れるが、100 では割り切れない」を表す条件式を書け。
  3. 「変数 y が 4 で割り切れるが、100 では割り切れない、あるいは 400 で割り切れる」を表す条件式を書け。
演習 5-2. 画像サイズの計算

(x × y) ピクセルの画像がある。 これを、(w × h) ピクセルの画面に フィットするように表示したい。 幅と高さ (x', y') の値を計算せよ。

x y w h 横フィット x y w h 縦フィット
  1. 横フィットの場合、x', y' を計算する式を書け。
  2. 縦フィットの場合、x', y' を計算する式を書け。
  3. x, y, w, h の値が与えられたとき、 この画像が横フィットになるような条件式を書け。

前回の課題について・補足

maxi.py
# リストの最大値を求める
a = [-3, 8, 19, -4]
maxi = 0
i = 0
while i < len(a):
??? ...
print(f"max index = {maxi}") print(f"max value = {a[maxi]}")

なぜ最大値そのものの値ではなく、maxi を求める必要があるのか? こうしておくと、以下のようなことが可能になるからである:

best_student.py
# 得点がもっとも高い学生の番号を表示する
student = [1234, 3456, 7890, 1111]
a = [-3, 8, 19, -4]
maxi = 0
i = 0
while i < len(a):
??? ...
print(f"max index = {maxi}") print(f"max value = {a[maxi]}") print(f"best student = {student[maxi]}")

1. プログラミングが苦手な人へ

有名な格言:

「プログラムは思ったようには動かないが、書いたようには動く」
  1. やることを自分の言葉で説明できなければ、プログラムは書けない
    繰り返すが、プログラミングに特別な能力は何も必要ない。 「自分のやらせたいことを、ひたすら書く」だけである。 しかし実は「自分のやらせたいこと」を 日本語で具体的に説明すること自体が簡単ではない。 これができるようになれば、あとはその説明を特定の プログラミング言語に変換するだけの機械的な作業である。
  2. 「何」ではなく「どうやって」に集中する
    たとえば小課題 3. でやった掛け算プログラムを考えてみよう:
    # 加減算のみを使って p×q を計算する。
    def multiple(p, q):
        a = 0
        while 0 < q:  # q回、p を足す。
            a = a + p
            q = q - 1
        return a
    
    ここで「掛け算ではなく、割り算を計算するプログラムを書け」と言われたらどうするだろうか。 「掛け算と割り算は逆だから、逆にすりゃいいだろう」と思って、 単純に +- 演算子にするだけでは動かない:
    # 加減算のみを使って p÷q を計算する。
    def divide(p, q):
        a = 0
        while 0 < q:
            a = a - p
            q = q + 1
        return a
    
    これは、考えてみれば当然である。 上の関数は divide と名前がついている (し、コメントにも ÷ と書いてある) が、本当に割り算をしているわけではない。 割り算をさせるには、見よう見真似でプログラムを「逆」にするだけではだめで、 実際に割り算をさせる手順を自分で考えて書かないとだめなのである。 しかし表面的な置換を「プログラミング」と勘違いしている人は時々いる。 プログラミングは、ファンタジーに出てくる魔法ではない。
  3. 1文字も間違わないように注意する
    「ちょっとぐらい違ってもいいじゃん」というタイプの人はプログラミングには向かない。
  4. ただひたすら訓練が必要な場合もある
    プログラミングが「得意」に見える人はただ Python などの言語に 慣れているだけで、別に頭が良いわけではない。 (本質的に難しい問題は、誰にとっても難しい。) ただし、ある程度訓練することで、プログラミングのかなりの部分は たいして考えなくてもできるようになる。

ここで格言をもう一度:

「プログラムは思ったようには動かないが、書いたようには動く」

2. 条件式 True と break文

以下のようなループを考える:

# 0から9まで表示する。
i = 0
while i < 10:
    print(i)
    i = i + 1

これと同じ処理は、条件式 Truebreak文を使って、 以下のように書くこともできる:

i = 0
while True:  # つねに真
    print(i)
    if i == 10:
        break  # i==10ならば抜ける
    i = i + 1

break文を実行すると、 一番近い while文から抜ける。

演習 5-3. ループ実行の予想

以下のようにすると出力結果はどう変わるか予想せよ。 実際に実行し、結果を確認せよ。

i = 0
while True:  # つねに真
    print(i)
    i = i + 1
    if i == 10:
        break  # i==10ならば抜ける

3. For文

ふたたび同じループを考える:

# 0から9まで表示する。
i = 0
while i < 10:
    print(i)
    i = i + 1

上のようなループは、for文を使うとより簡潔に書ける:

# 0から9まで表示する。
for i in range(10):
    print(i)
構文:
for 変数名 in range(繰り返し数):
    繰り返す文
    ...

このとき、変数名 の値は 0(繰り返し数 - 1) まで変化する。

例1: ループ中で条件分岐
for n in range(10):
    if (n % 2) == 0:
        print(f"{n}は偶数")
    else:
        print(f"{n}は奇数")

for文の中に if文などを書くこともできる。

例2: 九九の表示
for i in range(9):
    for j in range(9):
        x = i+1
        y = j+1
        print(f"{x} * {y} = {x*y}")

for文を二重にすると、 外側のfor文が一回まわるごとに 内側のfor文がすべて実行される。

例3: リストでfor文
a = [5, 9, 4, 0]
for i in range(len(a)):
    print(f"{i}番目の要素は {a[i]}")

range() 中は決まった数でなくてもよい。 len(a) (リスト a の長さ) を入れることで、 リストの全要素を表示できる。

4. 文字列

Python における文字列 (string) とは、 文字のリストである。

復習: コンピュータでは文字はどうやって表現されていたか?

構文:
例1:
s = "おうさまのみみはろばのみみ"
print(s[8])    # 「ろ」が表示される
print(len(s))  # 13

リストと同じように、文字列も最初の文字は「0文字目」です。

例2:
a = "お"
for i in range(4):
    a = a + "よ"
print(a)  # およよよよ

文字列はいくらでも + 記号で連結できる。

例3:
print("よろ" + "よろ")  # 「よろよろ」
print("よろ" - "よろ")  # エラー!

文字列は + 記号で連結できるが、引くことはできない。

例4:
a = "東工大"
a[1] = "京"  # エラー!

リストとは違って、Python では文字列の要素は変更できない

例5:
password = input("password:")
if password == "sesami":
    print("Correct!")
else:
    print("Wrong!")

数値と同じように、文字列に対しても == および != を使った条件式が使える。

例6:
空のリストがあるのと同様に、「空の文字列」というものも存在する。
name = ""

なお、input() 関数で何も入力せずにただ Enter を押すと、 空の文字列が返される。

演習 5-4. 図形を描く

以下のプログラムを実行すると、次の図形が表示される。

triangle.py:
# 三角形を表示する
for i in range(5):  # iは0〜4まで変化する。
    s = ""          # 空の文字列を準備する。
    for j in range(i+1):  # i+1回だけ繰り返す。
        s = s + "O"       # 文字列を延長する。
    print(s)
$ python triangle.py
O
OO
OOO
OOOO
OOOOO

このプログラムを改造して、 以下のような図形が表示されるプログラムを書け。 (行頭の部分は空白文字 " " を入れること)

OOOOO
 OOOO
  OOO
   OO
    O

4.1. リスト + 文字列

リストの中に文字列を入れることもできる。

names = ["睦月", "如月", "弥生", "卯月", "皐月", "水無月",
         "文月", "葉月", "長月", "神無月", "霜月", "師走"]
for m in range(12):
    print(f"{m+1}月は{names[m]}")
演習 5-5. 投票集計プログラムの改良 (本日の小課題)

前回の投票集計プログラムを改良し、番号でなく 候補者の名前を入力して投票できるようにしたい。 (ただ Enter のみが押されたらループを抜けるものとする。) 以下のプログラム vote3.py を完成させよ。

このプログラムを実行すると、以下のように動作する:

$ python vote3.py
name:trump
name:kim
name:abe
name:kim
name:    (Enter のみを押す)
abe: 1
trump: 1
kim: 2

なお、不正な文字列 (候補者のどれでもなく、空文字でもない文字列) が 入力される可能性は考えなくてよい。

vote3.py
# 候補者の名前
cands = ["abe", "trump", "kim"]
votes = [0, 0, 0]
while True:
    # 候補者の名前を入力する。
    name = input("name:")
    # name を候補者の名前と比較し、一致した候補者の票を増やす。
??? ...
# 3人の得票数を表示する。 for i in range(3): print(f"{cands[i]}: {votes[i]}")

5. データの「型」について

Python の変数に格納されるデータは、 実はいくつかの「 (type)」に分類されている:

+ 演算子の意味は、計算対象のデータ型によって異なる。

print(123+456)      # 整数 + 整数: 579
print("123"+"456")  # 文字列 + 文字列: "123456"
print(123+"456")    # 整数 + 文字列: エラー!

型が異なるデータの計算は意味をなさないので、ふつうはエラーが発生する。

5.1. 文字(列)型 → 整数型への変換

構文:
例1:
a = 123         # a は整数の 123
b = int("123")  # b は整数の 123
print(a+b)      # 整数+整数: 246
例2:
print(ord("A"))   # "A"の文字コード: 65
print(ord("あ"))  # 「あ」の文字コード: 12354
例3:
s = input("string:")
for i in range(len(s)):  # i は 0〜(文字数-1) まで変化する。
    print(ord(s[i]))     # i番目の文字コードを表示。
演習 5-6. 「日本」の文字コード

上の例3. のプログラムを実行し「日」「本」の各文字コードを調べよ。

input関数の動き

本来、Pythonのinput関数は入力された 文字列 (string) を返す。

s = input("string:")  # s は文字列型
print(s)

ここに int() 関数を適用することで、 文字列を整数型として利用できる。

s = input("number:")
x = int(s)  # x は文字列型
print(x)

5.2. 整数型 → 文字(列)型への変換

構文:
例1:
a = 123        # a は整数の 123
b = str(a)     # b は文字列の "123"
print(b+"0")   # 文字列+文字列: 1230
例2:
a = 9829
b = chr(a)         # b は Unicode 9829番 で表される文字
print("I"+b+"NY")  # I♥NY

chr()関数に与える文字コードは Unicode で定義されている。

例3:
for i in range(26):   # 26回繰り返す。
    print(chr(65+i))  # (65+i) で表されるUnicodeの文字を表示する。

このプログラムを実行すると、A から Z までの文字が表示される。

まとめると、以下のような関係がなりたつ:

文字 → 数値数値 → 文字
文字列int(x)str(x)
文字ord(x)chr(x)
演習 5-7. 英小文字だけを表示するプログラム

入力された文字列の中から英小文字だけを取り出して表示するプログラム loweronly.py を書け。 このプログラムを実行すると、次のように動作する:

$ python loweronly.py
string:ABCdef
def
$ python loweronly.py
string:123xyzFooBaa
xyzooaa

英小文字の文字コードは、 このページ で調べることができる。

loweronly.py
# 入力された文字列のうち、英小文字だけを表示する。
s = input("string:")
t = ""
for i in range(len(s)):
    c = ord(s[i])  # i番目の文字の文字コードをとりだす。
    # 英小文字であれば、変数 t の末尾に加える。
??? ...
# tの文字列を表示。 print(t)

5.3. print関数における f"〜""〜" の違い

じつは、print関数の機能は

構文:
print(文字列)  # 文字列を表示する。
だけであった。
print("hello")
print(f"x={x}")
などの書き方は、以下のようにもできる:
s = "hello"    # s は文字列型
print(s)       # s の内容を表示
t = f"x={x}"   # t は文字列型
print(t)       # t の内容を表示

さらに、 f"x={x}" は、 文字列の連結と str(x) 関数を 組み合わせたものと同じである:

t = "x=" + str(x)

6. 本日の課題

小課題 6. 投票集計プログラム vote3.py (11月15日締切)
vote3.py (再掲)
# 候補者の名前
cands = ["abe", "trump", "kim"]
votes = [0, 0, 0]
while True:
    # 候補者の名前を入力する。
    name = input("name:")
    # name を候補者の名前と比較し、一致した候補者の票を増やす。
??? ...
# 3人の得票数を表示する。 for i in range(3): print(f"{cands[i]}: {votes[i]}")

ヒント


Yusuke Shinyama