2018/07/26
2018/08/02 更新:inputを追加

【05.基礎2】Python基礎を学ぶ

どうも、ディープなクラゲです。
ゼロから学ぶディープラーニング推論」シリーズの5回目記事です。
このシリーズでは、Neural Compute StickとRaspberryPiの使い方をゼロから徹底的に学び、成果としてディープラーニングの推論アプリケーションが作れるようになることを目指しています。

第5回目は、Python基礎を学びます。
基礎から幅広く学ぶことも大事ですが、すぐに使わない項目を学んでも忘れてしまいます。
今回は実践的に「ゼロから学ぶディープラーニング推論」で使うPythonに絞ってじっくりと説明してゆきます!
ここで完全に理解しなくても、ディープラーニング推論を進める上で構文が出てきたときに「そういえばあったな」と思い出し、ここを見返せるようになれば良いかと思います。

【 目次 】


Pythonとは


Pythonはプログラミング言語の1つですが、特徴をあげると以下の3つです。

「スクリプト言語」とは、C言語やJAVAのようにコンパイルやビルドが不要で、プログラムを書いたら即実行が可能という意味です。
Pythonは、今回のようにディープラーニングや機械学習などに多く使われていますが、組込みやWebアプリケーションにもPythonは使われています。
構文のまとまりにカッコを使わず、インデント(字下げ)で表現するのが特徴的です

このシリーズで扱うPythonは主に以下の4つに分類できます

今回の記事では「Python基礎」を取り扱います。その他につきましては別の記事で取り扱います。

読み進めるにあたり、実際にコードを書いて実行しながら学習することを推奨します。
"nano test.py"でファイルを新規作成し、コードを貼り付けて保存し、"python3 test.py"で実行してください。

先頭行の #!

Pythonプログラムの先頭行を見ると "#!" で始まる以下のようなコードが書いてあります。
このコードから分かることは、このプログラムはpython3であるということです。実はこのコードは無くても動きます。

#! /usr/bin/env python3 

以下に詳細を書きますが、読み飛ばしても問題ありません。
例えばプログラムファイル名が"run.py"だったとき、ターミナルで"python3 run.py"としてコマンド実行した場合は、上記のコードは無視されます。上記のコードが有効になるのは "./run.py" で実行したときです。
"#!"は Shebang(シバン)と呼ばれるもので、起動してスクリプトを読み込むインタプリタを指定するための記述です。
"/usr/bin/env python3"は、環境変数PATHの中に含まれているpython3インタプリタを探して実行するという意味になります。
python3が正常にインストールされていれば、環境変数PATHの中にはpython3のパスが記述されています。
つまり、環境によらず正しくpython3を指定できるということです。

コメント

"#"記号を書くことで、その1行がコメント行になります。
コメント行とは、プログラム実行時に無視されるということです。主にプログラムに関する注釈を記述するために使用します。
ちなみに、先ほどの先頭行の"#!"はコメント行ではないので、ご注意ください。

#こんな感じで書きます 

import

PythonではNumPyやOpenCVなど様々な「モジュール」を読み込みます。
目的は「モジュール」の中にある複数の「関数」を活用するためです。「関数」については別途説明します。

モジュールの読み込み方法は主に3通りです。
numpyモジュールのzerosという関数を使用する場合を例に説明します。

import モジュール名

一番分かりやすい読み込み方法です
関数を使う場合は、モジュール名.関数名 で使います

import numpy
numpy.zeros(10)

import モジュール名 as 別名

as を加えれば、モジュール名を別名にして取り扱うことができます

import numpy as np
np.zeros(10)

from モジュール名 import 関数名

特定の関数しか使わない場合、この形式で書くことにより、関数使用時にモジュール名が不要になります

from numpy import zeros
zeros(10)

変数・代入・演算

他のスクリプト言語同様、変数の型宣言は不要です。整数も小数も文字列も同じように扱えます。
また代入は他のプログラミング言語同様 = を用いて、左側に右側の値を代入します。

= 2018
= 3.14
= 'jellyfish'

記号 + - * / を用いて四則演算可能です。+= や *= の代入演算も使えます。
例えば、以下のコードの1行目と2行目は同じ意味になります。

= a + 1
+= 1

なお、Pythonでは a++ のようなインクリメント演算子はありません

文字列

文字列はシングルクォート ' もしくは ダブルクォート " で囲みます。
文字列を表示するには以下のような形でprintを使います。

print('hello jellyfish')
 
# 実行結果 
# hello jellyfish 

文字列は + を用いて簡単に連結させることが出来ます。

print('hello' + ' jellyfish')
 
# 実行結果 
# hello jellyfish 

文字列に \n を使うと改行できます。
なお、pythonのprint文は末尾に自動的に改行が入ります

print('hello\n jellyfish')
print('Deep Learning')
 
# 実行結果 
# hello 
#  jellyfish 
# Deep Learning 

型変換

printにて文字列と数値を連結して出力するとエラーになります。
そこで数値をstrを使って文字列化させて出力させます。

= 12.345
print(str(a) + "%")
 
# 以下だとエラー 
# print(a + "%") 
 
# 実行結果 
# 12.345% 

逆にintを使って文字列を数値化させることもできます

= '100'
= int(a)/2
 
# 以下だとエラー 
# b = a/2 

その他、floatを使うと整数から小数への変換もできます

条件分岐

他のプログラミングと同様にifを使って条件分岐を行います。注意点は、コロン、インデント、elifの綴りです。
代表的な書き方3つで見ていきます。

if

まずは if だけの場合
変数levelの値が0の場合は'Beginner'と表示し、0以外は何も行わないプログラムです。
"==" は比較演算子と呼ばれるもので、左側の変数と右側の値が同じであるか否かをチェックし、同じである場合はインデントされたブロックを実行します。インデントとは字下げのことで、Pythonではスペース4つを使います。今回は1行しかありませんが、ブロックは複数の構文があっても構いません。条件式の後にはコロン : をつけ忘れないようにしましょう。

level = 0
if level == 0:
    print('Beginner')
 
# 実行結果 
# Beginner 

if...elif

複数の分岐を行いたい場合は elif を使います。"else if"の略です
変数levelの値が 0, 1, 2 それぞれに応じて表示結果が異なります。

level = 2
if level == 0:
    print('Beginner')
elif level == 1:
    print('Intermediate')
elif level == 2:
    print('Advanced')
 
# 実行結果 
# Advanced 

if...elif...else

条件分岐のどれにもあてはまらない場合に対し、処理をさせたい場合は else を最後に追加します。
変数levelの値が 0, 1, 2 以外のときは"Master!!"と表示されます。

level = 99
if level == 0:
    print('Beginner')
elif level == 1:
    print('Intermediate')
elif level == 2:
    print('Advanced')
else:
    print('Master!!')
 
# 実行結果 
# Master!! 

リスト

リストは他のプログラミングでいうところの配列にあたります
簡単に言うと、一つの値ではなく、一連の値を格納できる変数です。
代表的な使い方を見てゆきます

初期化

このように各要素をカンマで区切り、カッコ[ ]内に記述します。

= [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

リストの中にリストを書くことにより多次元のリストも扱えます

= [[10, 20, 30], [100, 200, 300]]

要素なしで初期化することも可能です(後から要素を追加できます)

= []

追加(append)

appendを使うことにより要素を追加できます

= [10, 20]
a.append(30)
print(a)
 
# 実行結果 
# [10, 20, 30] 

要素数(len)

lenを使うとリストの要素数を知ることができます

= [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
= len(a)
print(b)
 
# 実行結果 
# 10 

要素の参照

"リスト名[n]" でリストの要素にアクセスできます
Pythonでは要素番号は 0 から始まります。例えば n が 5 の場合は 6番目 の要素をアクセスすることになります。

= [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
= a[5]
print(b)
 
# 実行結果 
# 60 

スライス

"リスト名[n:m]"を使うとリストから条件にあった要素全てを取り出すことができます
取り出される要素は n ~ m-1 番目です。 m-1 というのがちょっとややこしいですね。
実際のプログラムで確かめてみましょう。

= [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
= a[2:5]
print(b)
 
# 実行結果 
# [30, 40, 50] 

n もしくは m を省略することもできます。
n を省略した場合は 最初 ~ m-1 まで、 m を省略した場合は n ~ 最後までを取り出します。

= [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
 
= a[:5]
print(b)
 
= a[2:]
print(c)
 
# 実行結果 
# [10, 20, 30, 40, 50] 
# [30, 40, 50, 60, 70, 80, 90, 100] 

反転リスト [::-1]

"リスト名 [::-1]" という書き方で、反転したリストを得ることができます。
スライスは [n : m : s] や、負の数を指定したりできます。詳細説明は割愛しますが、この複合技が [::-1] という訳です

= [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
= a[::-1]
print(b)
 
# 実行結果 
# [100, 90, 80, 70, 60, 50, 40, 30, 20, 10] 

タプル

タプルとは要素を変更できないリストです。初期化時のカッコがリストと異なります。
参照やスライスなどリストと同じように扱うことができます。

= (102030405060708090100)
= a[5]
print(b)
 
# 実行結果 
# 60 

繰り返し

繰り返しには while と for があります。

while True

whileは主に無限にループさせたいときに使います。また合わせて無限ループから抜け出すbreakも同時に使われます。
無限ループにする場合はwhileの条件式を True にします。ifと同じようにブロックはインデントする必要があります。

num = 0
while True:
    print(num)
    if num >= 5:
        break
    num = num + 1
 
# 実行結果 
# 0 
# 1 
# 2 
# 3 
# 4 
# 5 

for in

forは主にリストと一緒に使います。
"for A in B:" という形式で、ブロックはインデントします。
今回のシリーズではrangeを使用した2通りの書き方を使っています。

range(n, m) の場合は n ~ m-1 までの値を i に代入してブロックを繰り返します。

= [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
for i in range(2, 5):
    print(a[i])
 
# 実行結果 
# 30 
# 40 
# 50 

range(n) の場合は 0 ~ n-1 までの値を i に代入してブロックを繰り返します。

= [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
for i in range(5):
    print(a[i])
 
# 実行結果 
# 10 
# 20 
# 30 
# 40 
# 50 

関数

関数とは、入力値を受け取り、処理を行った後、出力値を結果として返すものです。
入力値を「引数」、出力値を「戻り値」と呼びます。
具体例として、半径を引数とし、円周を求める処理を行い、円周値を戻り値として返す関数 circle を作ってみましょう。

関数は def で定義します。
"def 関数名(引数):" を記述した後にインデントを行い、処理をブロックに書きます。
円周の公式は 2 × π × r なので、変数 l に対して "l = 2 * 3.14 * r" で代入を行っています。
"return 戻り値" で結果を返すことができます。

def circle(r):
    l = 2 * 3.14 * r
    return l

関数を作ったら、関数を呼び出します。具体的に引数に 10 を入れて呼び出してみましょう。

def circle(r):
    l = 2 * 3.14 * r
    return l
 
val = circle(10)
print(val)
 
# 実行結果 
# 62.800000000000004 

関数の引数や戻り値は1つではなく複数でもOKです。
以下は、半径と円周率を引数として円周と円の面積を返す関数の例です。

def circle(r, pi):
    l = 2 * pi * r
    s = pi * r * r
    return l, s
 
val1, val2 = circle(10, 3.14)
print(val1)
print(val2)
 
# 実行結果 
# 62.800000000000004 
# 314.0 

if __name __ == "__main__":

この記述がプログラム中に出てきた場合、どのような流れでプログラムが実行されるかについて説明します。
非常に簡単で、このifのブロックに書いてある処理が実行されるという意味です。ブロックに書いてあるのは、ほとんどのケースで main関数呼び出しです。つまり、まとめると「main関数が実行される」というただそれだけのことです。

if __name __ == "__main__":
    main()

以下の記述も全く同じ流れです。 sys.exitが付いていると後でコマンドから終了ステータスが確認できるだけの違いです。

if __name __ == "__main__":
    sys.exit(main())

以下に詳細を書きますが、読み飛ばしても問題ありません。
この記述の存在理由について簡単に説明します。
先程の記述があるプログラムを普通に実行した場合は先程の説明の通り「main関数が実行される」だけです。
効果があるのは、別のプログラムからimportして、特定の関数だけを使いたい場合です。先程の記述がないと、importしたときに不要な処理が実行されてしまいます。一方で、先ほどの記述があると、importしても main関数など不要な処理は実行されなくなります。
つまり、まとめると先ほどの記述は「普通に実行」と「他のプログラムからimport」を両立させるための処理ということです。

その他

input

inputを使うと、ユーザーがキーボードから入力した文字列を受け取れます。
Enterキーが押されるまでの文字列が入力対象です。

print('What is your name?')
= input()
print('Your name is ' + a)
 
# 実行結果 
# What is your name? 
# kurage 
# Your name is kurage 

ファイル読み込み(with open ... as)

プログラム中にファイルを読み込むときには read を使いますが、最初にopenした後にreadを行い、最後にcloseするというお作法があります。pythonでは、withを使ってブロックを抜け出したときに自動的にcloseするという方法があり、よく使用されています。
ファイルオープン時にはモードを指定できます。rは読み出し専用、bはバイナリモードという意味です。datafileをファイルオブジェクト名 f として開き、f.readを行ってdataに代入しています。
つまり簡単にまとめると「変数dataへファイルdatafileの中身を代入している」だけです。今回はファイル読み込みについてはあまり深入りせず、この最後のまとめ程度の認識で大丈夫です。

with open(datafile, mode='rb') as f:
    data = f.read()

%記号を使ったprint

printで数値と文字列を組合せて表示させる際の方法としてstr関数で文字列化させる以外に%記号を使ってフォーマット表示する方法があります。%記号を使うと細かな数値表現が可能になります。
例えば変数 a を小数で表現させるには '%f' % a と記述します。
さらに小数点以下1桁で表現したい場合は '%.1f' を使います。
さらに全体で6桁表現にしたい場合は '6.1f' と記述します。6桁に満たない場合はその分、スペースが挿入されます
%記号を使っているときに、%文字列を表示させたい場合は '%%'と書きます。

= 12.345
print('%f' % a)
print('%.1f' % a)
print('%6.1f' % a)
print('%6.1f%%' % a)
 
# 実行結果 
# 12.345000 
# 12.3 
#   12.3 
#   12.3% 

quit

quitはプログラムを途中で終了させます。
以下のコードの例では、whileループにてcntを1ずつ増加させて3以上になった時点でquitを実行しています。
whileループの外にある print('end') が実行されずにプログラムは終了されます。

cnt = 0
print('start')
 
while True:
    cnt = cnt + 1
    print(cnt)
    if cnt >=3:
        quit()
 
print('end')
 
# 実行結果 
# start 
# 1 
# 2 
# 3 

min, max

minは引数に与えられた値の中から最小値を返します。
maxは引数に与えられた値の中から最大値を返します。

= min(40, 20, 50, 10, 30)
print(a)
 
= max(40, 20, 50, 10, 30)
print(b)
 
# 実行結果 
# start 
# 10 
# 50 

os.system

pythonプログラム中にLinuxコマンドを実行させることができます。
osモジュールをimportして使用します

import os
 
os.system('ls')

これで今回のサンプルソースで使用するPythonを一通り学びました。次回は「NumPy」について学びます。
以上、「Python基礎を学ぶ」でした。