応用プログラミング及び実習 2019年度 第2回 Notebook

プログラミング言語 Python (前編)

Python とは

Python は,プログラミング言語 の一種である.C言語と比較すると,同様の処理をより簡単に書ける点が大きな特徴である. 例えば,C言語のプログラム

#include <stdio.h>

int main(void)
{
    printf("Hello World!\n");

    return 0;
}

と同様のものを Python で書くと,次のようになる.

print("Hello World\n");

簡単に書けることから,旧来の言語(C言語など)に比べて習得や使用が容易と言われることもある(本当にそうかはこれから身をもって体感してください). 簡単に書けるという意味で類似の言語には,Perl, Ruby などがある.

Python プログラムの実行の仕方

前回体験したように,Python のプログラムは様々なやり方で実行できる. この notebook 上では,数行のプログラムの断片(コードスニペットと呼ばれることがある)をその場で実行して結果を即座に確認できる. 一方, hoge.py のような名前のテキストファイルにプログラムを書いて,次のようにコマンドラインから実行することもできる.

$ python  hoge.py

これらの実行はどのような仕組みになっているのだろう.

C言語の場合, hoge.c のようなソースファイルを作ったら,それを実行するには次のような手順を経る:

  1. ソースをコンパイルして実行形式のファイルを作る

    $ cc  hoge.c  -o  hoge
  2. 実行形式のファイルを実行する

    $ ./hoge

コンパイルというのは,人間が理解しやすい形のプログラムを,コンピュータが理解しやすい形の機械語プログラムに翻訳する作業のことだった. この場合,プログラム実行時には,あらかじめ翻訳済みの機械語プログラムをコンピュータが(CPUが)読解して実行していくことになる.

一方,Python プログラムの実行の場合,上述のようにファイル hoge.py を python というコマンドに渡して実行してもらっている. この python コマンドは,人間が理解しやすい形で書かれた hoge.py の中身を,上から順に逐次翻訳しながら実行する仕事をしている. 翻訳者が事前にプログラム全体を翻訳しておくやり方と,通訳者が同時通訳するやり方の違い,といえばよいだろうか.

C言語の場合は,ccコマンドで実行されるコンパイラが翻訳者に相当する.翻訳が済んでしませば翻訳者は用済みなので,実行の際には実行形式のファイルを直接指定するだけでよい.一方,Python の場合は,実行の際に逐次通訳してもらいながら実行するので,通訳者である python コマンドを呼び出して実行する必要がある.

この notebook のような仕組みは,Python の実行が上記のような仕組みになっているからこそ実現できている面もある.

このような,人間向けのプログラムをコンピュータ向けのプログラムに翻訳する過程をどのように処理するかという点は,プログラミング言語の性質・特徴を決める重要なポイントである.それぞれのやり方に長所短所があるのだが,この授業ではこれ以上は立ち入らないことにする.

Python プログラミングの初歩 (2)

この資料中に説明なくページ番号が出てくる場合,教科書のページ番号を表しています.

前回の復習+α

以下のセルの print(x) の行の前に,x という名前の変数に整数値 4649 を代入する式を書いて実行しなさい.

In [ ]:
print(x)

以下の実行結果がどうなるか予想してから,実行してみなさい

In [ ]:
print(x  / 10)
print(x // 10)

以下の実行結果がどうなるか予想してから,実行してみなさい

In [ ]:
x++
x

上記のセルの1行目は,変数 x の値に 1 を加えたものを x に代入しようとしたのだが,エラーになってしまった. これを修正しなさい.ただし, 複合演算子 を使うこと(x = x + 1 はNG).

以下の実行結果がどうなるか予想してから,実行してみなさい.

In [ ]:
y = 5960 + int(3.14)
y

以下の実行結果がどうなるか予想してから,実行してみなさい.

In [ ]:
s1 = "ほげ"
s2 = "ふが"
s1 * 3 + s2

以下の実行結果がどうなるか予想してから,実行してみなさい.

In [ ]:
s1 = "10月"
s2 = 2
date = s1 + s2 + "日"

上記がエラーになるのは,変数 s1 は文字列を,変数 s2 は整数値を表しており,3行めで,これら異なる型の変数の値同士で s1 + s2+ 演算を行おうとしたからである.このエラーを解消するには,いくつかの方法がある.以下の例をそれぞれ実行してみなさい.

  1. s2 に代入する値をダブルクォーテーションまたはシングルクォーテーションで囲って文字列( "2" )にする.
  2. 上記を元に戻して,3行目の式の s2str(s2) とする.

前回,リストというデータ型について学んだ.これは,次のように,複数の要素をならべたものをまとめて扱ったりするためのものである.

In [ ]:
list1 = [ 1, 2, 3, 4, 5 ]
print(list1)
print(list1[0], list1[2], list1[4])

list2 = [ "ほげ", "ふが", "へな"]
print(list2)
print(list2[-1])

2つのリストに対する + 演算の結果は,それぞれのリストの要素を連結したリストになるのだった.

In [ ]:
list3 = list1 + list2
list3

上記から明らかなように,リストの要素には様々なデータ型のものが混在しても構わない(前回の話には出てきてない & 教科書でも説明されてないところ).したがって,こんなリストもあり.

In [ ]:
L = [ 1, 2, 3.14159, "ほげ", [5, 9, 6, 3] ]
print(L)
print(L[3])
print(L[4])

リストを使う(後半, pp.68-76)

pp.68-70を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
mcz = ["れに", "あかり", "かなこ", "しおり", "あやか", "ゆきな"]
mcz
In [ ]:
mcz[5] = 'ももか'
mcz
In [ ]:
del mcz[0]
mcz

以下のセルの1行目,2行目に書き加えて,L の3番目(0から数えて3番目)の要素を "ふが" にして,2番目の要素を削除しなさい.

In [ ]:
L

pp.70-72を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
momotamai = mcz[1:3]
momotamai
In [ ]:
mcz[:2]
In [ ]:
mcz[1:]

上記の [1:3], [:2], [1:] のような要素番号の指定の仕方をすると,元のリストの一部を切り出したリストを得ることができる. これをスライスという. 元のリストから要素が削除されるわけではない.

Lという名前のリストに対して L[a:b] とすると,L[a] から L[b] の1つ手前まで,すなわち L[a] から L[b-1] までの要素を含むリストが得られる.:(コロン) の後ろに指定した番号の要素は含まれないということである.慣れないと間違いやすいので要注意.

上記の例から分かるように,コロンの前/後を省略すると「先頭から」/「末尾まで」と指定することになる.

以下のセルの2行目をスライスを使って書き換えて,出力が ['参', 4, '五', 6, 7, 'はち'] となるようにしなさい.

In [ ]:
L2 = [ 0, 1, 2.0, "参", 4, "五", 6, 7, "はち", 9, 10]
print(L2)

同様に,[0, 1, 2.0, '参'] および ['はち', 9, 10] となるようにしなさい.コロンの前後どちらかの数を省略する書き方をすること.

リスト L2 は10個の要素を含んでいる.コロンの後の数を省略しない書き方で8番目以降の要素を取り出すにはどうしたらよいだろう. 考えてから,次の2つを実行しなさい.

In [ ]:
print(L2[8:9])
print(L2[8:10])
In [ ]:
#(よだんだよん)
print(L2[:])
print(L2[5:-1])
print(L2[8:3])

pp.72-74を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
city_temps = [
    [14.8, 14.8, 15.1, 15.4, 15.2, 15.4, 17.0, 16.9],  # 東京都
    [10.0, 10.4, 11.5, 11.2, 10.9, 10.6, 11.8, 12.2],  # 秋田市
    [16.0, 15.5, 15.9, 16.4, 15.9, 15.6, 17.5, 17.1]   #熊本市
]
In [ ]:
city_temps[1]
In [ ]:
city_temps[2][7]- city_temps[2][0]
In [ ]:
# Notebook上でグラフを描くための準備
%matplotlib inline
import matplotlib.pyplot as plt

plt.plot(city_temps[0])       # 東京都のグラフを描画
plt.plot(city_temps[1])       # 秋田市のグラフを描画
plt.plot(city_temps[2])       # 熊本市のグラフを描画

上記の2次元配列のようなものは,リストのリストとして実現している.C言語の2次元配列と違って,外側のリストの要素となるリストたちは要素数が異なっても構わないので,こんなリストも作れる.

In [ ]:
L3 = [ mcz, [11, 22, 33], L2 ]
L3
In [ ]:
L3[2][8]

pp.74,75を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
monk_fish_team = [158, 157, 163, 157, 145]
sum(monk_fish_team)
In [ ]:
max(monk_fish_team)
In [ ]:
min(monk_fish_team)

上記で使っている sum(), max(), min() は,Pythonに標準で備わっている組み込み関数である.

pp.75,76を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
len(monk_fish_team)
In [ ]:
monk_sum = sum(monk_fish_team) 
monk_len = len(monk_fish_team)    
monk_mean = monk_sum/monk_len
monk_mean
In [ ]:
plt.bar([0, 1, 2, 3, 4], monk_fish_team)
plt.plot([0, len(monk_fish_team)], [monk_mean, monk_mean], color='red')

len() も Python の組み込み関数である.引数にリストを渡せばその要素数を返してくれる. len()に文字列を渡すと...

In [ ]:
len("ほげほげほげ")

(よだんだよん) グラフを描く matplotlib のバージョンが上がって,環境によっては上記では教科書の図と同じ見た目のグラフにならないかも.その場合は以下のようにしたらよいだろう.

In [ ]:
x = [0, 1, 2, 3, 4]
plt.bar(x, monk_fish_team)
plt.plot([x[0], x[-1]], [monk_mean, monk_mean], color='red')

for文でループを使う (pp.77-82)

pp.77-79を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
mcz = ['れに', 'かなこ', 'しおり', 'あやか', 'ももか']
for member in mcz:
    print(member)

Python の for 文の書き方は,C言語とはかなり違っている.

for  ループ変数  in  シーケンス:
    繰り返し実行するブロック
  • シーケンス には,リストのように要素を一つずつ取り出せるものを指定.上の例ではリストを表す変数 mcz を指定している.
  • シーケンスの先頭から順に取り出した要素が ループ変数 に代入され,それぞれの要素ごとに 繰り返し実行するブロック が実行される.
  • for の行の最後には :(コロン)をつける.その次の行から,インデント(字下げ)して繰り返し実行するブロックを書く.

上で「シーケンスの先頭から順に取り出した要素がループ変数に代入され」 と書いたが,例えば上の例でリスト mcz から要素が削除されてしまうわけではない.

In [ ]:
mcz

以下の実行結果がどうなるか予想してから,実行してみなさい.

In [ ]:
for x in [1, 3, 5, 7, 9]:
    print(x, x**2)
print("ほげ")

上記の3行目をインデントして再実行してみなさい.

In [ ]:
L2

以下の実行結果がどうなるか予想してから,実行してみなさい.

In [ ]:
for x in L2[3:8]:
    print(x, end=" ")   # このように書くと,改行する代わりにスペースを出力する

$ x_1, x_2, \dots , x_N $ という $N$ 個の実数値があったとき,これらの平均を $\mu$ とおくと, \begin{align} \mu = \frac{1}{N}\sum_{n=1}^{N} x_n \end{align} となる.また,標準偏差を $\sigma$ (分散は $\sigma^2$)とおくと, \begin{align} \sigma^2 = \frac{1}{N}\sum_{n=1}^{N} (x_n - \mu)^2 \end{align} となる.

pp.79-81を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
monk_fish_team = [158, 157, 163, 157, 145]

total = sum(monk_fish_team)
length = len(monk_fish_team)
mean = total/length
variance = 0

for height in monk_fish_team:
    variance = variance+(height-mean)**2

variance = variance/length
variance
In [ ]:
variance**0.5
In [ ]:
volleyball_team = [143, 167, 170, 165]

total2 = sum(volleyball_team)
length2 = len(volleyball_team)
mean2 = total2/length2
variance2 = 0

for height in volleyball_team:
    variance2 = variance2+(height-mean2)**2

variance2 = variance2/length2
variance2**0.5

(よだんだよん) 後日学ぶことだが,Pythonでは,プログラミング言語として標準で備わっている機能に加えて,様々な拡張機能(科学技術計算,機械学習,データ分析,画像処理,ゲーム開発,etc.)を読み込んで動作させることができる. 例えば,科学技術計算のモジュール NumPy ( https://www.numpy.org/ ) を用いると,上記の計算はこんな感じに書ける.

In [ ]:
import numpy as np   #  NumPy モジュールを np という名前で使えるようにする
vec = np.array([143, 167, 170, 165])   # NumPy の配列
print(np.mean(vec))  # 平均
print(np.sqrt(np.var(vec)))     # 分散の平方根 = 標準偏差

pp.81,82を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
for cnt in range(10):
    print(cnt)

この例では出力が 0 から 9 までなことに注意. range(n)0 から n-1 までの整数のシーケンスを返す.

「これやと複雑な繰り返しとか書きにくいやん,3から始めるとか,奇数だけとか…」と思いました? 実は組み込み関数 range() にはもっと機能があるので,いろいろできます.教科書p.197参照.

In [ ]:
savings = 100
for i in range(15):
    savings = savings+savings*0.05

savings

リストの要素を順に取り出して処理する繰り返しは以下のその1のように書けるが,その2のように,組み込み関数 len()range() を使って書くこともできる.

In [ ]:
# その1
for x in L2:
    print(x)
In [ ]:
# その2
for i in range(len(L2)):   # 0 から (L2 の要素数) - 1 まで
    print(i, L2[i])              # これだとループ変数を要素番号として扱える

(よだんだよん) 組み込み関数 `enumerate()` を使う手もある(p.199).

In [ ]:
for i, x in enumerate(L2):
    print(i, x)

if文で条件分岐をする (pp.83-92)

pp.83-86を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
if 2*2*2+2 == 10:
    print("2*2*2+2は10")
if 2+2*2+2 == 10:
    print("2+2*2+2は10")
if (2+2)*2+2 == 10:
    print("(2+2)*2+2は10")

Python の if 文の最も基本的な書き方は,次の通り.

if  条件式:
    条件が真だったときだけ実行するブロック
  • 条件式には,例えばx に整数が代入されているとした場合の x > 0x == 5953 のように,結果が 真 (True)偽(False) のいずれかになるような式を書く.
  • if の行の最後には :(コロン)をつける.その次の行から,インデント(字下げ)して条件が真だったときだけ実行するブロックを書く.
In [ ]:
# 数の比較

if 1 == 1:
    print("1番目はTrue")
if 5^(4-4)+9 == 10:     # 教科書はこうなっているが, `^` は本当は`**` と書きたかったのかもしれない
    print("2番目はTrue")
if 2 < len([0, 1, 2]):
    print("3番目はTrue")
if sum([1, 2, 3, 4]) < 10:
    print("4番目はTrue")
In [ ]:
# 文字列同士の比較

if "AUG" == "AUG":
    print("1番目はTrue")
if "AUG" == "aug":
    print("2番目はTrue")
if "あいう" == "あいう":
    print("3番目はTrue")

pp.86-88を読んで理解したら,以下のセルを実行しなさい.

In [ ]:
# 文字列に対する in 演算子の働き

if "GAG" in "AUGACGGAGCUU":
    print("1番目はTrue")
if "恋と戦いはあらゆることが正当化されるのよ" in "正当化":
    print("2番目はTrue")
if "stumble" in "A horse may stumble though he has four legs":
    print("3番目はTrue")

in は,for文のときにも出てきましたね. x in y という式は,y の要素に x が含まれていれば True,さもなくば False になります(上記の2番目が False なことに注意).

In [ ]:
# リスト同士の比較

if [1, 2, 3, 4] == [1, 2, 3, 4]:
    print("1番目はTrue")
if [1, 2, 3] == [2, 3]:
    print("2番目はTrue")
if [1, 2, 3] == ['1', '2', '3']:
    print("3番目はTrue")

上記に2行追加して, [1, 2, 3][2, 3, 1] が等しいと判定されたら 4番目はTrue と出力するようにしなさい. 実行して動作を確認しなさい.

In [ ]:
# リストに対する in 演算子の働き

if 2 in [2, 3, 5, 7, 11]:
    print("1番目はTrue")
if 21 in [13, 17, 19, 23, 29]:
    print("2番目はTrue")
if 'アッサム' in ['ダージリン', 'アッサム', 'オレンジペコ']:
    print("3番目はTrue")
In [ ]:
# 2番目3番目はよく考えないといけない例

if 1 in [0, 1, 2, 3, 4]:
    print("1番目はTrue")
if [1, 2] in [0, 1, 2, 3, 4]:   # これで 「1か2が含まれていたら True になるわけではない
    print("2番目はTrue")
if [1, 2] in [0, 1, [1, 2], 3, 4]:
    print("3番目はTrue")

以下はpp.88-92と同様の内容を説明したものですが,教科書とは違う例を使ってます. 理解しながら読み進めて,各セルを実行して動作確認しなさい.

Python の if 文では,C言語と同様に if-else 型の条件判定も書ける. 2箇所の : を忘れずに.

if  条件式:
    条件が真だったときだけ実行するブロック
else:
    条件が偽だったときだけ実行するブロック
In [ ]:
# else の例 (教科書とはちょっと違う)

if 2*3-2+4 == 10:
    print("式1は10")
else:
    print("式1は10にならない")
if 2**3-2+4 == 10:
    print("式2は10")
else:
    print("式2は10にならない")

C言語で if-else が入れ子にできる(if-else の中に さらに if-else 書いたりできる)のと同じように, Python の if 文も入れ子にできる

int y = 10;
if (y < 20){
    ...
}else{
    if (y < 30){
        ...
    }else{
       ...
    }
}

C言語で上記の例に相当するものを, Python では例えば次のように書く. 1行目の 19 をいろいろ変えて動作確認しよう.

In [ ]:
y = 19
if y < 20:
    print("こども")
else:
    if y < 30:
        print("夢も希望もある大人")
    else:
        print("夢も希望もある大人...が眩しく見える大人")

5行目のif文の条件式は y < 30 だけですが,このブロック(5行目以降)は4行目の else の中なので,「y < 20がFalse 」の時だけ実行されます. したがって,「夢も希望もある大人」と出力されるのは,「y < 20 が False かつ y < 30 が True のとき」つまり「yが20以上30未満」のときだけですね.

Python では elif 文というものが使える. elseif を組み合わせた形. 上記の例は,次のように書き直せる.先の例と同じように y の値をいろいろ変えて動作確認しよう.

In [ ]:
y = 19
if y < 20:
    print("こども")
elif y < 30:
    print("夢も希望もある大人")
else:
        print("夢も希望もある大人...が眩しく見える大人")

(よだんだよん) Python には C言語の `switch` に相当するものはありません.`elif` ずらずら並べます.

当然,for文やif文は組み合わせて使うことができる. a_num の値をいろいろ変えて実行してみよう.

In [ ]:
# p.92 の例
a_num = 57
for num in range(2, a_num):  # range(a, b) は a から b-1 まで
    if a_num % num == 0:
        print(a_num, "は素数ではありません")
        break          # C言語同様にループを抜ける

チェック

TAさんに課題Aのチェックを受ける際は,以下のセルを実行して「OK!」が出ているようにしてください.

In [ ]:
# 以下のコードは,この notebook を(それなりに)ちゃんと実行したかどうか確認するためのものです.
# 中身の理解は不要です.

fnpy = '/roes/sample/takataka/aprog/aprogCheck.py'
import os
if not os.path.isfile(fnpy):
    print('この環境では確認できないようです')
else:
    import sys
    sys.path.append('/roes/sample/takataka/aprog/')
    import aprogCheck
    aprogCheck.check('02note', In)