この一連の資料を通して、プログラミング言語Pythonを用いて大気海洋分野のデータ解析や数値シミュレーションの基礎を解説することを目指します。 Pythonは、非常に多彩なライブラリ(拡張機能群)の力を借りることで力を発揮する言語です。(例:Numpy, Matplotlib, Pandas...) 今回は、その第一段階としてライブラリ無しの「生の」Pythonの文法を基礎から学びましょう。
Pythonプログラムは ○○.py という名前のテキストファイルに命令が一行一行書かれたもので、それを読み取って実行することでプログラムが実行されます。
この文書は、Jupyter labのノートブック形式で作成されています。 ノートブックはひとまとまりの「セル」が並んだ構造をしており、ここのようにテキストで書かれたセルと、数行のPythonの命令(グレーの背景)およびその結果を記したセルとをまとめて表示してくれます。 一つのページで説明と例を見ながら学んでいくことになります。ぜひ手元に実行環境を構築し、例を真似したり改変したりして理解を深めつつ読み進めてください。
それでは、早速Pythonの基礎を学んでいきましょう。
_を用いることができます。print, if, for, importなど一部の文字列はPython自体によって予約されており、自分で勝手に使うことはできません。#以降は読み取られません。コメントに用います。print(○○)は、カッコ内の変数などを文字として書き出す機能です。変数にどんな数が入っているのかなど、状況確認に非常によく使います。print("Hello, world!") # "Hello, world!" という文字列を出力する
a = 5 # 変数aに5を代入する
b = -2 # 変数bに-2を代入する
print(a+b) # a+bを出力する
b = 10 # 変数bに10を代入する、-2は上書きされる
print(a+b) # a+bを出力する
整数型や浮動小数点型の変数は、計算式に当てはめていろいろな計算を行えます。
+, -, *, ///%**(例:2の8乗は2**8)() は通常の数式と同様、計算の順番を指定します。式の解釈に曖昧さがあるときは、特に使うようにしましょう。数以外の型にも演算が定義されていることがあります。例えば文字列どうしの足し算 + は、文字列の結合を意味します。
# 上のセルのa=5, b=10を記憶している
c = a - b
print(c)
print(c**2)
myname = "Fujiwara"
print("My name is " + myname)
24 ÷ 6 ÷ 2は解釈のしようによって結果が2通りあります。それぞれの場合を曖昧さが残らないように数式で表し、結果をprintしましょう。
たとえば100人分の試験の点数を扱いたいときに、score1, score2, score3...と一つ一つ変数を用意していてはきりがありません。
そういったときは、データの「列」である配列を用います。
Pythonでは配列にあたる型がいくつもありますが、ここでは「リスト」を紹介します。
# リストは角カッコで定義し、中に要素をカンマで区切って入れていく
mylist1 = [0, 3, 1.5]
mylist2 = [c, c**2, c**3, c**4] # 上のc=-5を記憶している
mylist3 = ["apple", "orange"] # リストの要素はどんな型でもいい
# リストの足し算はリストの結合を表す
numbers = mylist1 + mylist2
print(numbers)
# len()はリストの要素数を返す関数
print(len(numbers))
配列の要素は、角カッコで0から始まる要素番号を与えることで取り出せます。
# numbers = [0, 3, 1.5, -5, 25, -125, 625]
print(numbers[0]) # 一番前:0
print(numbers[2]) # 0から数え始めて2番目:1.5
print(numbers[-1]) # マイナスはリストの最後から数える:625
print(numbers[10]) # リストをはみ出す番号はエラーを吐きます
「2番目から4番目」や「偶数番目」のように、複数の要素を抜き出すこともできます。スライスと呼びます。
スライスは、[start:end:interval]のように表記し、「start番目からend番目の手前まで、interval個おきに」要素を取り出します。
ここで、end番目自体はスライスに含まれないことに注意しましょう。癖がありますが、慣れると思います。
startを省略すると配列の最初の要素から、endを省略すると配列の最後の要素まで、intervalを省略すると要素を飛ばさないという意味になります。
# numbers = [0, 3, 1.5, -5, 25, -125, 625]
print(numbers[3:5]) # 0から数え始めて、3番目から5番目の手前まで
print(numbers[:-3]) # 最初の要素から、後から3番目の手前まで
print(numbers[::2]) # 0, 2, 4,...番目
まず、0から30までの、偶数のリストを作りましょう。後で説明するrange関数を用います。
x = list(range(0, 30, 2))
print(x)
xができたら、次の要素を取り出すにはどうすればよいでしょうか。
最後に、配列の長さ(要素数)を得る関数としてlen関数を紹介します。len関数は文字列の長さ(文字数)にも用いられます。
print(len([1,5,0])) # 3
print(len([5])) # 1
print(len([])) # 空っぽのリストの長さはゼロ
a = list(range(10, 2000, 30)) # 10から始まって2000を超えない範囲の、30おきの等差数列
print(len(a))
上で説明した通り、すべての変数にはその種別を表す型があります。 型によって、定義されている操作が異なるのでその確認は非常に重要です。
変数の型は、type(変数)によって確認できます。型には以下のようなものがあります。
int 整数 (integer)float 実数 (浮動小数点数、floating-point number)complex 複素数 (complex number)str 文字列 (string)bool 論理型list リストtuple タプルfunc 関数np.ndarray ndarray (NumPyの回で説明します)x = 3
y = 3.14
z = "3.14"
print(type(x))
print(type(y))
print(type(z))
実数→整数や整数→文字列、リスト→np.ndarrayなどのように、型を変換したいことが出てきます。
そのようなときは、型名(変数)とすると型を変換できます。
# y = 3.14, z = "3.14"
print(y + float(z)) # 実数 + 実数
print(str(y) + z) # 文字列 + 文字列
print(y + z) # 実数 + 文字列、怒られる
同じ処理をたくさん繰り返したいときは、ループを用いるのが有効です。Pythonでの代表的なループ構文は、for構文です。
for文は for ○○ in 配列等: という構文から始まります。コロン:を忘れないようにしましょう。
配列の成分をひとつづつ取り出して、それを○○として、それに続く行頭が字下げされた「ブロック」内の処理を繰り返し行います。
字下げ(インデント)はPythonでプログラムのひとまとまりを指定する方法で、for(あるいは次に説明するif)などの影響を受ける範囲を明確に指定するために、字下げの有無やスペースの個数の一貫性は厳密に守る必要があります。
# 例:リスト[1, 2, 3]の要素をnとして、n+10を順にprintする
for n in [1,2,3]:
# 字下げされた部分を繰り返す
a = n + 10
print(a)
print("inside loop")
# 行頭が戻ったので、ここ以降は繰り返さない
print("end of loop")
for構文のin以下には、配列のように順番をもつ(変数[0]のように要素を指定できる)変数が入ります。
中でも多く使うのはrange関数で、range(start, end, interval)によって、「初項start, 公差interval, 末項がendの手前までの等差数列」が作られます。
intervalやstartは省略可能で、省略した場合interval=1, start=0と解釈されます。
以下の例ではrange(6)の要素を順にnに代入して、nの2乗を順にprintしてゆきます。
# 例: n=0から5までのnについて、n**2をprintする
# range(6)はrange(0, 6)およびrange(0, 6, 1)と同じで、[0,1,2,3,4,5]のこと
for n in range(6):
print(n**2)
# 例: 単純に「n回繰り返す」というときもrange(n)が使えます
for n in range(3):
print("Hello")
最初の例でお見せした通り、for ... in の後ろには、range以外にもリストなどを入れられます。その場合、配列の成分を前から順に拾ってゆきます。
# 例: a = ["orange", "apple", "banana", "peach"]について、順に"I like ○○"という文をprintする
a = ["orange", "apple", "banana", "peach"]
for fruit in a:
print("I like " + fruit)
級数$\sum$などは繰り返し構文で計算できます。はじめに変数totalにゼロを設定しておき、for構文内でtotalに第1項、第2項...と順に足してゆけばよいのです。
実用ではNumpyなどのライブラリを用いればより高速に計算できますが、基本的な計算の仕組みを知っておくのは非常に大事です。
# 例: 等比級数 1 + 1/2 + 1/4 + 1/8 + ... の部分和を10項めまでprintする
sum = 0 # 合計、最初にゼロに設定しておく
for n in range(10):
sum = sum + 1 / (2**n) # べき乗は掛け算割り算より優先されるので、1 / 2**nと書いても同じ
print(sum)
次の操作をfor文を使って書いてみましょう。
x = 10
y = 12
z = 15
print(x < y) # True
s = x < y # s = Trueのように、変数に割り当てることもよくある
t = x > z # t = False
print(s and t) # True and False = False
print(s or t) # True or False = True
print(s and (not t)) # True and True = True
ある条件のときは特定の処理を行う、ということをif文によって行えます。
if文は、if 論理式:という構文から始まり、論理式がTrueならば、それ以下のブロック内の処理を実行します。コロン:を忘れないように!
# 上のセルから、x=10, y=12
if x <= y:
print("x is smaller than y")
if x == y:
# Falseなので実行されない
print("x is equal to y")
また、条件を枝分かれさせることもできます。if ... else構文ではifの条件が満たされなかった場合はelse以下の処理が実行されます。
さらにif ... elif ... else構文ではifの条件が満たされなかった場合はelif(else ifの略です)の条件の判別が行われ、それも満たされなかった場合はelse以下の処理が実行されます。elifの分岐の個数はゼロ個を含め何個でもよく、elseもあってもなくても構いません。
like_meat = False
if like_meat:
lunch = "Tonkatsu"
else:
lunch = "Sandwich"
print(lunch)
like_meat = False
like_fish = True
if like_meat:
lunch = "Tonkatsu"
elif like_fish:
lunch = "Sushi"
else:
lunch = "Sandwich"
print(lunch)
# 応用例:数字nが素数 (prime number) かどうかを判別する
n = 47 # 1以上の数字、自由に変えられる
if n == 1:
prime = False
else:
# 2以上n未満の数字のすべてで割り切れなかったら素数
prime = True # はじめにTrueとしておき、どこかで割り切れたらFalseに書き換える
for c in range(2, n):
if n % c == 0:
prime = False
# 結果の書き出し
if prime:
print("n is a prime number")
else:
print("n is not a prime number")
条件分岐を使って、2つの数nとmの大小を判別するプログラムを組んでみましょう。
いろんなn, mの組み合わせについてプログラムが正常に動作していることを確かめましょう。
# いくつかの例
def func(x):
return x**2 - 5*x + 3
def absolute(x):
# 絶対値を返す
# こういった単純な処理は自分で作らなくてもすでにPythonやNumpyに入っていますが、
# 中身の処理を理解するのによい例です
if x >= 0:
absx = x
else:
absx = -x
return absx
print(func(10))
print(absolute(10))
print(absolute(-5))
y = absolute(-2) + func(3)*0.5 # 普通に計算式に組み込めます
print(y) # |-2| + 0.5 * (3**2 - 5*3 + 3) = +0.5
# 数字だけでなく、論理式や文字列を返す関数も作れます
def is_prime(n):
# 素数ならTrue, そうでなければFalseを返す関数、前例の流用
if n == 1:
prime = False
else:
# 2以上n未満の数字のすべてで割り切れなかったら素数
prime = True # はじめにTrueとしておき、どこかで割り切れたらFalseに書き換える
for c in range(2, n):
if n % c == 0:
prime = False
return prime
def odd_or_even(n):
# 奇数なら"odd number", 偶数なら"even number", それ以外なら"not integer"(整数ではない)を返す関数
if n % 2 == 1:
result = "odd number"
elif n % 2 == 0:
result = "even number"
else:
result = "not integer"
return result
print(is_prime(10))
print(is_prime(101))
print(odd_or_even(10))
print(odd_or_even(10.5))
引数が複数の関数も同様に作れます。例えばxとyとzを引数とする場合def f(x,y,z):のかたちで関数定義を行い、関数呼び出しの際には同じ数の引数を与えます。
また、引数がない関数も作れます。その場合も関数定義の構文のカッコは飛ばさずdef f():の形で定義し、関数呼び出しの際もf()とカッコ付きで呼び出します。
ある決まった値を得るために関数を使う必要性は薄いですが、後で説明するように関数内で行う処理を目的として引数無しの関数を使う場合があります。
def func(x, y, z):
return z - (x**2 + y**2)
print(func(0, 1, 2)) # x=0, y=1, z=2
print(func(-3, 4, 30)) # x=-3, y=4, z=30
def const():
return 3.141592
print(2*const())
また、関数の引数にデフォルト値を設定することもできます。例えばy=10, z=20をデフォルトとする場合def func(x, y=10, z=20):のように、定義時にイコールでデフォルト値を設定します。
デフォルト値を設定すれば、関数呼び出しの際にその引数を省略することができます。
# デフォルト値を指定する例
def func(x, y=10, z=20):
return z - (x**2 + y**2)
print(func(0)) # x=0, y=10, z=20
print(func(0, 5, 10)) # x=0, y=5, z=10
print(func(0, z=10)) # x=0, y=10, z=10
def greeting(name, message="Good morning!"):
return "Hi " + name + ", " + message
print(greeting("Ichiro"))
print(greeting("Jiro", "Good afternoon!"))
関数は値を返すだけでなく、その中で処理を行わせることを目的として使うこともできます。この場合、return ○○を与えずにそのまま字下げを戻すか、returnのみで関数を終わらせることができます。
# nの約数を出力する
def print_divisor(n):
for m in range(1,n+1):
if n % m == 0:
# m = 1~nまでで、nがmで割り切れたらprint
print(m)
print_divisor(72)
# 引数無しの関数
def greet():
print("Good morning")
greet()
greet()
ここでは詳細まで解説しませんが、関数外にも同名の変数があるときに関数内で変数を上書きすると、基本的には外側の変数は書き換えられません。 これには変数のスコープが関係しており、関数内でglobal文でスコープを変更してやることで変数上書きの影響範囲を変えることができます。
# localスコープとglobalスコープの例
x = 10
def update_x():
x = 100
print("update_x: after overwriting", x)
def update_global_x():
global x
x = 100
print("update_global_x: after overwriting", x)
print("outside:", x)
update_x()
print("outside:", x)
update_global_x()
print("outside:", x)
関数の使い方に慣れましょう。
xとし、(x+5) / (x-5)を返す関数を定義しましょう。nとし、"Hello"をn回printする関数を定義しましょう。nについて呼び出しましょう。簡単にまとめるのみにとどめますが、必要に応じて使ってみたり勉強してみましょう。