Pythonの基礎#
# 警告メッセージを非表示
import warnings
warnings.filterwarnings("ignore")
最初の注意点#
半角と全角#
半角を基本としてコード(スペースも含めて)を書くこと。
次の2つケース以外で全角を使うとエラーが発生する。
以下で説明する文字列型のデータ型の場合は全角を使っても構わない。
半角の
#
の後であれば全角を使っても構わない(Python
は#
の後に続くコードを無視するためであり,よくコメントを書くのに使われる)。
例えば,次のコード・セルには半角の10
の後に全角のスペースが紛れ込んでいるためエラーが発生している。
10
Cell In[2], line 1
10
^
SyntaxError: invalid non-printable character U+3000
「全角スペース忍者」には要注意!
左詰め#
Python
ではインデントが重要な役割を果たします。原則,コード・セルの中で左詰めでコードを書くようにすること。一方で,以下で説明するようにインデントが必須な場合(例えば,for
ループや関数を定義する場合)もあり,その様な場合は半角スペース4つを入れるのが慣例となっている。Jupyter NotebookやJupyterLab (Desktop)ではTab
を押すことにより半角スペース4つが自動で挿入されるので覚えておこう。
括弧#
コードでは括弧が多用されるが,次の呼称とする。
()
:丸括弧(parentheses)[]
:角括弧(brackets){}
:波括弧(braces, curly braces, curly brackets)
4つの基本データ型(Data Types)#
Python
には無数のデータ型があるが、まず,基本的なデータ型(data types)となる次の4つを紹介する。
整数型(int)
浮動小数点型(float)
文字列型(str)
ブール型(bool)
整数型(int
)
157
157
浮動小数点型(float
)
3.14
3.14
文字列型(str
)
ダブルクォート"
もしくはシングルクォート'
を使う
"apple"
'apple'
'pear'
'pear'
↓↓↓ も文字列
'100'
'100'
ブール型(bool
)
真偽値とも呼ばれる。
True
True
True
は1
として計算に使うことができる。
False
False
False
は0
として計算に使うことができる。
算術演算子#
+
(加算; addition)-
(減算; subtraction)*
(乗算; multiplication)/
(除算; division)//
(切り捨て除算; 実数の整数部分; floor division)%
(剰余演算; 余りを取得する演算; modulo)**
(累乗; exponentiation)
加算
10 + 1
11
True
は1
,False
は0
と等しいので次の計算が成立する。
True + 10
11
False + 10
10
+
は文字列にも使える。
'I' + ' like' + ' Kobe'
'I like Kobe'
減算
1 - 0.5
0.5
乗算
(10 - 2) * 2
16
除算
5 / 2
2.5
切り捨て除算(floor division)
以下では分子・分母が正の値の場合だけを考える
5 // 2 # 5/2=2.5
2
剰余演算
以下では分母が正の値の場合だけを考える
5 % 2 # 5÷2=2 余り 1
1
累乗
4 ** 2
16
関係演算子#
==
(等号)!=
(等号不成立)<
(小なり)>
(大なり)<=
(小なりイコール)>=
(大なりイコール)
評価結果としてTrue
もしくはFalse
が返される。
10 == 10
True
10 != 10
False
10 > 5
True
10>=10
True
10<=10
True
True == 1
True
False == 0
True
理論演算子#
a & b (aとbの両方)
a | b (a又はb又は両方)
~a (aではない)
割り当て演算子#
割り当て演算子(assignment operator):
=
変数\(x\)に値10
を「代入」するには等号=
を使う。
x = 10
また\(x\)の値を表示すには,次のように\(x\)を書いたセルを評価するだけである。
x
10
1つのセルに複数行で書くと,上から順に実行する。
x = 10
x
10
ここで「代入」に使った=
について少し説明する。実は,=
は「代入」ではない。更には,x
と10
は別物なのである。これを理解するために,多くの品物が保管されている大きな倉庫を考えてみよう。倉庫の管理者はどの品物がどこに保管されているかを記録する在庫リスト(記録帳やコンピューター・ファイル)を作成し,そこに品物が保管されている棚を示す記号を記入しているとしよう。この例を使うと,
10
→ 倉庫の棚に保管されている品物x
→ 在庫リストに記載されている棚の記号
となる。品物と棚の記号は別物なのである。Python
では,品物である10
がコンピューター内のメモリーの所定の場所に保存され,その場所を示すのが変数x
となる。即ち,x
は品物10
の実態とは異なる単なる「参照記号」なのである。
10
→ PCのメモリーに保存されている情報x
→ 参照記号
この点を明確にするために,上のコードは「x
に10
を代入する」と考えるのではなく,「10
を記号x
に割り当てる」と考える。ここで,式を右から左に読んでいることに注意しよう。左から右に読んで「記号x
を10
に割り当てる」と考えないことを推奨する。意味は同じだが,=
を右から左に読む(考える)ことを習慣づけることが,今後Python
を勉強する上で重要となるからである。この点を示すために次のコードを考えてみよう。
x = x + 1
「?」と思うかもしれない。暗に方程式として考えるためであろう(私がそうだった)。これを右から左に読むとスッキリする。
一番上のコードで
10
をx
に割り当てたが,問題のコードの右辺のx
がその10
である。10
に1
を加えたものが11
であり,それが右辺である。=
を使い右辺の11
を左辺のx
に割り当てている。この時点で,10
の参照記号であったx
は11
の参照記号に変更される。
実際にx
を表示してみよう。
x
11
この例では,記号x
は10
を指していたが11
に変更されている。これは,同じ記号を複数の「品物」の参照記号に使えないためである。一方で,同じ「品物」を複数の参照記号に割り当てる事は可能である(例えば,y=x
)。いずれにしろ「品物と参照記号の関係」は今の段階ではそれ程重要ではないが,先に進むにつれて重要性が増してくるので,今のうちにこのようなイメージを持つと良いだろう。
変数名に使う記号について#
変数の名前を作る上で守らなくてはならないルールがある。
(a-z, A-Z)
もしくは_
(アンダースコア)で始める最初の文字以外であれば
(a-z, A-Z)
と_
に加え数字も可長さに制限はない
小文字と大文字は異なる記号としてあつかう
次の単語は特定の目的のために事前に定義されているため,変数名としては使えない。
import keyword
keyword.kwlist
['False',
'None',
'True',
'and',
'as',
'assert',
'async',
'await',
'break',
'class',
'continue',
'def',
'del',
'elif',
'else',
'except',
'finally',
'for',
'from',
'global',
'if',
'import',
'in',
'is',
'lambda',
'nonlocal',
'not',
'or',
'pass',
'raise',
'return',
'try',
'while',
'with',
'yield']
これらに加え,
変数の頭文字は小文字とする
というのが慣例(エラーにはならない)であり,大文字で始まる変数はclass
と呼ばれるオブジェクトに使う。
また#
は実行されないコメントを書くときに使われる。以下の例では,1+2
は実行されるが#
で始まる行は無視される。
# この行はコメント
y = 1 + 2
# この行もコメント
y # この箇所もコメント
3
コレクション系データ型#
コレクション系とは上で説明した基本データ型の集まりとなるデータ型で,ここでは以下を簡単に説明する。
リスト(list)
タプル(tuple)
辞書(dict)
集合(set)
リストを作るには[]
を使う。
lst0 = [10, True , 'apple']
lst0
[10, True, 'apple']
タプルは()
を使って作成する。
tpl0 = ('A', True, 100)
tpl0
('A', True, 100)
リストと変わりないように見えるが,大きな違いは要素を変更できるかできないかという点である。
リストの要素は変更可能
タプルの要素は変更不可能
リストの要素の変更方法は以下で説明する。
<コメント>
上で通常タプルは(
と)
を使って作成できると説明したが,実は,コンマ,
によってタプルは定義されるため(
と)
は必須ではない。例えば,次のコードでもタプルとなる。従って,(
と)
はタプルを明確にするためと考えて良い。
tpl1 = 'B', False, -100
tpl1
('B', False, -100)
辞書はキー(key)と値(value)のペアとなって定義され,:
を挟んで1つのペアとなる。全てを{}
で囲み辞書を定義する。
dct0 = {'a':10, 'b':'Kobe'}
dct0
{'a': 10, 'b': 'Kobe'}
dict0
には2つのペアがある。a
のキーには値10
が対応しており,b
には'Kobe'
が設定されている。今の段階では辞書を使う目的が不明確でしっくりこないと思うが,勉強を進めるととてもパワフルなツールだと気づくだろう。
集合は使う機会がないので説明は割愛する。
コレクション系とは上で説明した基本データ型の集まりとなるデータ型で,ここでは以下を簡単に説明する。
リスト(list)
タプル(tuple)
辞書(dict)
集合(set)
リストは[]
を使う。
list0 = [10, 3 , 2]
list0
[10, 3, 2]
以下もリストの一例である。
list1 = ['A', True, 100]
type(list1)
list
print(type(list1))
<class 'list'>
上で説明したように,print()
は定義したリストを画面上に表示する関数であり,print()
を使うとlist
というクラス(class)であることも確認できる。
タプルは()
を使って作成する。
tuple0 = ('A', True, 100)
print(tuple0)
('A', True, 100)
リストと変わりないように見えるが,大きな違いは要素を変更できるかできないかという点である。
リストの要素は変更可能
タプルの要素は変更不可能
リストの要素の変更方法は以下で説明する。
<コメント1>
上で通常タプルは(
と)
を使って作成できると説明したが,実は,コンマ,
によってタプルは定義されるため(
と)
は必須ではない。例えば,次のコードでもタプルとなる。従って,(
と)
はタプルを明確にするためと考えて良い。
tuple1 = 'B', False, -100
print(tuple1)
print(type(tuple1))
('B', False, -100)
<class 'tuple'>
<コメント2>
1つの要素からなるタプルを作成する場合,コンマ,
が必ず必要となる。
tuple2 = (10,)
print(tuple2)
print(type(tuple2))
(10,)
<class 'tuple'>
コンマ,
がないとタプルとはならない。
tuple3 = (10)
print(tuple3)
print(type(tuple3))
10
<class 'int'>
辞書はキー(key)と値(value)のペアとなって定義され,:
を挟んで1つのペアとなる。全てを{}
で囲み辞書を定義する。
dict0 = {'a':10, 'b':'Kobe'}
dict0
には2つのペアがある。a
のキーには値10
が対応しており,b
には'Kobe'
が設定されている。今の段階では辞書を使う目的が不明確でしっくりこないと思うが,勉強を進めるととてもパワフルなツールだと気づくだろう。
type(dict0)
dict
print(type(dict0))
<class 'dict'>
集合は使う機会がないので説明は割愛する。
要素の抽出方法#
各要素の抽出#
まずリストの要素の数え方を説明する。次の図のように左から0
,1
,2
…,右からは-1
,-2
,-3
と数える。
0 1 2 3 4 5 (左から数える)
+---+---+---+---+---+---+
| A | B | C | D | E | F |
+---+---+---+---+---+---+
-6 -5 -4 -3 -2 -1 (右から数える)
lst1 = ['A', 'B', 'C', 'D', 'E', 'F']
の場合,'A'
は0
番目,'B'
は1
番目,'C'
は2
番目と数える。ここでの,0
,1
,1
をインデックス(index)と呼ぶ。
要素のアクセス方法:
[]
とインデックス番号を使う。
例えば,A
を抽出したい場合,
lst1[0]
'A'
最後の要素にアクセスするには次のようにする。
lst1[-1]
'F'
連続する複数の要素の抽出#
連続する複数の要素を選択する場合(スライシング)は:
を使う。
:
の左側が選択する最初の要素:
の右側が選択する最後の次の番号
B
(1番目),C
とD
(3番目)を抽出したい場合を考えよう。
lst1[1:4]
['B', 'C', 'D']
次のように書くとより直観的かもしれない。
lst1[1:3+1]
['B', 'C', 'D']
次のルールも覚えておこう:
:
の左側の番号を省略すると「最初から全て」となる。:
の右側を省略すると「最後まで全て」となる。
lst1[:4]
['A', 'B', 'C', 'D']
lst1[1:]
['B', 'C', 'D', 'E', 'F']
タプルも同じ#
タプルも同じ方法で要素を抽出できる。
tpl1 = ('A', 'B', 'C', 'D', 'E', 'F')
tpl1[2]
'C'
tpl1[1:3+1]
('B', 'C', 'D')
文字列も同じ#
文字列も同じ方法で要素を抽出できる。
str0 = 'University'
str0[3]
'v'
str0[1:3+1]
'niv'
辞書は異なる#
辞書の場合はキーで指定する。
dct1 = {'a':10, 'b':'apple', 'c':[1,2,5]}
dct1['a']
10
dct1['c']
[1, 2, 5]
複数指定する場合は,for loop
などの複雑な手法が必要となる。
要素の入れ替え#
リストの場合#
上で作成したlst1
を考えよう。
lst1
['A', 'B', 'C', 'D', 'E', 'F']
2
番目にあるC
を100
に入れ替えたい場合,次のようにする。
=
を使う。=
の左側にC
を抽出するコードを書く。=
の右側に100
を書く。
コードを書いてみよう。
lst1[2] = 100
lst1
['A', 'B', 100, 'D', 'E', 'F']
タプルと文字列の場合#
タプルと文字列は変更不可であるため,要素の入れ替えはできない。
辞書の場合#
上で作成したdct1
を考えよう。
dct1
{'a': 10, 'b': 'apple', 'c': [1, 2, 5]}
apple
をpear
に入れ替えたい場合,次のようにする。
=
を使う。=
の左側にapple
を抽出するコードを書く。=
の右側にpear
を書く。
コードを書いてみよう。
dct1['b'] = 'pear'
dct1
{'a': 10, 'b': 'pear', 'c': [1, 2, 5]}
要素の追加#
リストの場合#
上で作成したlst1
を考えよう。
lst1
['A', 'B', 100, 'D', 'E', 'F']
最後に3.14
を追加したい場合,メソッド.append()
を使う。メソッドについては,以下でより詳しく説明するので,ここではコードだけを紹介する。
lst1.append(3.14)
lst1
['A', 'B', 100, 'D', 'E', 'F', 3.14]
タプルの場合#
変更不可なので,要素の追加はできない。
文字列#
次の文字列を考えよう。
moji = 'Kobe'
moji
'Kobe'
Univ
を追加する場合,+
を使うことができる。
moji = moji + ' Univ'
moji
'Kobe Univ'
辞書の場合#
上で作成したdct1
を考えよう。
dct1
{'a': 10, 'b': 'pear', 'c': [1, 2, 5]}
新たな要素d:3.14
を追加したい場合,次のようにする。
=
を使う。=
の左側に,あたかもd
を抽出するようなコードを書く。=
の右側に3.14
を書く。
コードを書いてみよう。
dct1['d'] = 3.14
dct1
{'a': 10, 'b': 'pear', 'c': [1, 2, 5], 'd': 3.14}
組み込み関数#
Python
が起動すると,直ぐに使えるように様々な関数が用意されており組み込み関数(built-in functions)と呼ばれる。
print()
#
print()
は表示するための関数であり,引数に表示したい値を置く。Jupyter Notebookではprint()
を使わなくとも出力が表示される。例えば,
10
10
しかし複数行の場合は最後の行しか表示されない。
10
200
200
print()
を使うと両方を表示することができる。
print(10)
print(200)
10
200
異なるオブジェクトを表示するには,
を使う。
print('2020年の実質GDP:約', 500+25.7, '兆円')
2020年の実質GDP:約 525.7 兆円
文字列の中で\n
は改行を示す。
print('マクロ\n経済学')
マクロ
経済学
次にf-string
(formatted string literal; フォーマット済み文字列リテラル)を紹介する。文字列の前にf
を書き加え,文字列の中で{}
を使うことにより,割り当てた変数の値や計算結果などを表示することが可能となる。次の例を考えよう。
x = 2/3
print(f'3分の2は{x}です。')
3分の2は0.6666666666666666です。
四捨五入し小数点第3位まで表示する場合は,x
の後に:.3f
を付け加える。
print(f'3分の2は約{x:.3f}です。')
3分の2は約0.667です。
<:.3f
の解釈>
:
はこの後に続くコードは表示に関するものだと「宣言」している。.
は小数点表示に関しての設定であることを示している。3
は小数点第3位を示している。f
はfloat
のf
3f
を5f
にすると,小数点第5位までの四捨五入となる。試してみよう。
sum()
#
合計を返す関数
x = [1, 2, 3, 4, 5, 6]
sum(x)
21
len()
#
要素数を返す関数
len(x)
6
x
の平均は次のように計算できる。
sum(x) / len(x)
3.5
abs()
#
絶対値を返す関数
abs(-10)
10
range()
#
等差数列のオブジェクトを用意する関数
range(start,stop,step)
start
:最初の整数(引数を与えない場合は0
)stop
:最後の整数の次の値step
:隣接する整数の差(公差)(引数を与えない場合は1
)
例えば,0から9までの10の整数を準備するには
range(10)
range(0, 10)
0
から10
までの整数が表示されないが,使えるように裏で準備されている。
次のコードは0
から999,999,999
(10億-1)までの10億個の整数を準備している。
range(1_000_000_000)
range(0, 1000000000)
一瞬にして10億個の整数が準備される「驚愕の速さ!」と言いたいが、実は、「準備」されただけで、10億個の整数が生成された訳ではない。実際に使うときに、0
、1
、2
、3
、、、と順番に整数の生成が実行されことになる。このように、各整数を使うときに「実行」することを遅延評価(lazy evaluation)と呼ぶ。「何のために使うの?」と思うだろう。理由は高速化のためであり、実際に10億個の整数からなるリストの作成には数十秒もしくは数分掛かる。例えば、次のシナリオを考えてみよう。10億個の正の整数のルートを計算するとし、計算プロセスが始まった後に計算する整数の数は(確率的に)決まるとしよう。10億個全ての整数を使うかもしれないが、もしかすると、7万個、もしくはたった5個の整数のルート計算だけで終わるかもしれない。その場合、10億個の整数を事前に準備する時間は無駄になるかも知れないし、あまりにも非効率的な手順だということは直ぐに理解できるのではないだろうか。順番に0
、1
、2
、3
、、、と必要な場合に整数の作成を実行する方が断然効率的だ。このように遅延評価するオブジェクトをジェネレーター(generator)と呼ぶ。range()
関数は、for
ループではよく使う関数なので覚えておこう!
list()
#
リストを作成する関数
z = range(10)
list(z)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(10)
で準備された0
から9
までの整数を使って,リストを作成している。次のコードを実行すると10億個の整数からなるリストを作成することができる。アンコメントして(#
を削除して)実行すると、終了まで数分掛かるだろう!You are warned!
# list( range(1_000_000_000) )
ユーザー定義関数#
最も簡単な例#
組み込み関数以外に,ユーザーは自由に関数を作成することができる。コードを書くうえでユーザー定義関数は非常に重要な役割を果たす。
関数には引数が設定されるが(省略される場合もある),複数の種類がある。ここでは基本となる引数のみを考えるが,引数の位置と=
が重要な役割を果たすことになる。
最初の例は数字の2乗を計算する関数である。
def squared(x):
return x**2
説明:
1行目:
def
で始まり(def
はdefinitionの省略形):
で終わる。squared
が関数名,x
が第1引数(ひきすう)であり唯一の引数である。
2行目:
return
は評価した値を「返す」もしくは「戻す」という意味。return
の前には4つの半角スペースが必要である。x**2
という返り値(戻り値)の設定をする
関数を評価するには,引数に数字を入れて実行する。
squared(2)
4
(注意)
関数を定義する場合の引数(上の例では
x
)は「仮引数」(parameter)と呼ぶ。関数を評価する際に関数に引き渡す引数(上の例では
2
)は「実引数」(argument)と呼ぶ。以下では両方を「引数」と呼ぶ。
引数が無い関数を定義することを可能である。
def func_kobe():
return 'I love Kobe :)'
func_kobe()
'I love Kobe :)'
引数の位置が重要#
上の例では引数が1つしかないが,引数が複数ある場合にその位置が重要になってくる。次の例を考えよう。
def division(a, b):
return a / b
division(10, 2)
5.0
a
が第1引数,b
が第2引数である。引数の順番を間違えると意図しない結果につながる。
division(2, 10)
0.2
もちろん,3つ以上の位置引数も設定可能である。
def my_func(a, b, c, d):
return (a - b) / (c + d)
my_func(10, 20, 30, 40)
-0.14285714285714285
実行する際に=
を使う#
関数を実行する際に,引数に=
を使って値を指定することも可能である。
division(a=10, b=2)
5.0
この場合,引数の順番を変えることが可能となる。それが関数を実行する際に=
を使う利点である。
division(b=2, a=10)
5.0
この場合,全ての引数に=
を使わないとエラーとなる。
division(10, a=2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[106], line 1
----> 1 division(10, a=2)
TypeError: division() got multiple values for argument 'a'
理由は最初の10
をa
の値と解釈されるためである。一方で,引数の位置が揃っていれば,全ての引数に=
を付ける必要はない。
my_func(10, 20, d=40, c=30)
-0.14285714285714285
ここでも引数の位置が重要な役割を果たしている。
定義する際に=
を使う#
関数を定義する際,=
を使って引数のデフォルトの値を設定することができる。即ち,引数を入力すると入力された数値を使うが,引数を入力しない場合は引数を予め設定した値(デフォルトの値)が使われて評価される。次の例ではc
のデフォルトの値が10
に設定されている。
def another_func(a, b, c=10):
return (a + b) * c
c
の値を与えずに評価してみる。
another_func(2, 3)
50
次にc
にデフォルトと異なる値を設定してみる。
another_func(2, 3, 100)
500
(Note)
関数を実行する際に
=
無しで関数に渡される引数は,その位置が重要であるため「位置引数」と呼ばれる。関数を実行する際に
=
付きで関数に渡される引数は「キーワード引数」と呼ばれる。
オブジェクトとメソッド#
オブジェクト#
Python
を習うと「オブジェクト」という単語が必ず出てくる。今の内にイメージをつかむために自転車をオブジェクトの例として考えてみよう。通常の自転車には車輪が2つあり,サドルが1つあり,左右にペダルが2つある。これらの数字が自転車に関するデータである。またペダルを踏むことにより前に動き,ハンドルを右にきると右方向に進むことになる。即ち,あることを実行すると,ある結果が返されるのである。これは数学の関数と同じように理解できる。\(y=x^2\)の場合,\(x\)が2
であれば\(y\)の値として4
が返される。このように自転車はデータと関数が備わっているオブジェクトとして考えることができる。また,車輪の数やペダルを踏むことは自転車特有のデータと関数であり,他のオブジェクト(例えば,冷蔵庫)にはない。即ち,世の中の「オブジェクト」にはそれぞれ異なるデータと関数が存在していると考えることができる。
Python
の世界でも「すべて」をこれと同じように考え,データを属性と呼び,関数をメソッドと呼ぶ。整数型10
を例にあげると,単なる数字に見えるが,実は様々な属性とメソッドから構成されるオブジェクトなのである。
属性(attributes)は
10
が持つ様々なデータ(例えば,10
という値や整数型という情報)メソッド(methods)は
10
特有の関数(例えば,加算,除算のように10
というデータに働きかける関数)
自転車と冷蔵庫は異なるデータと関数を持つように,整数型10
と文字列型神戸大学
は異なるデータと関数を備えるオブジェクトなのである。この考え方はPython
のすべてに当てはまる。即ち,Everything is an object in Python.
(メソッドも属性の一種と考えることもできるが,以下では上の分け方に沿ってPython
の使い方を説明する。)
メソッド#
例えば,上で定義したdivision()
や組み込み関数sum()
は関数であり,特定のオブジェクトに働きかけるものではない。単に引数から計算した返り値を出力しており,計算できる引数である限りどのようなオブジェクトでも構わない。一方,メソッドは元々オブジェクトに備わっている関数である。例として,文字列I love 神戸!
を考えよう。I love 神戸!
というオブジェクトには様々なメソッドが用意されており,そのリストをdir()
という組み込み関数を使うことにより表示できる。
moji = 'I love 神戸!'
dir(moji)
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__getnewargs__',
'__getstate__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mod__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__rmod__',
'__rmul__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'capitalize',
'casefold',
'center',
'count',
'encode',
'endswith',
'expandtabs',
'find',
'format',
'format_map',
'index',
'isalnum',
'isalpha',
'isascii',
'isdecimal',
'isdigit',
'isidentifier',
'islower',
'isnumeric',
'isprintable',
'isspace',
'istitle',
'isupper',
'join',
'ljust',
'lower',
'lstrip',
'maketrans',
'partition',
'removeprefix',
'removesuffix',
'replace',
'rfind',
'rindex',
'rjust',
'rpartition',
'rsplit',
'rstrip',
'split',
'splitlines',
'startswith',
'strip',
'swapcase',
'title',
'translate',
'upper',
'zfill']
アルファベット順に並んでいることが分かる。例として,メソッドupper
を使ってみる。
moji.upper()
'I LOVE 神戸!'
upper
はアルファベットを大文字に変換するメソッドであり,moji
にもともと備わっている関数である。
Note
moji
の後に.upper()
が来ており()
に引数がないように見えるが,実は先にあるmoji
を引数としてupper()
を実行しているのである。upper
はメソッドの名前であって,実行するには()
が必要となる。つけ忘れるとオブジェクトのデータ型が表示されることになる。これは関数と同じである。
_
はアンダースコア(underscore)と呼ぶが,2つ連続した場合__
となりダブル・アンダースコア(double underscore)と呼ぶ。長いのでダンダー(dunder)と省略する場合が多々ある。上のリストにはこのダンダーに挟まれたメソッドが含まれている(ダンダー・メソッドと呼ばれる)。これらは対応するコードを実行するとPythonが裏で使うメソッドであるため,直接コードに書く必要はない。
「全てがオブジェクト」なのでリストもそうである。
lst = [4, 3, 9, 0, 1]
dir(lst)
['__add__',
'__class__',
'__class_getitem__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__getstate__',
'__gt__',
'__hash__',
'__iadd__',
'__imul__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__reversed__',
'__rmul__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']
この中にappend
とあるが,for
ループの説明で使ったメソッドである。
lst.append(100)
lst
[4, 3, 9, 0, 1, 100]
他にsort
とあるがこれは要素を昇順に並び替えるメソッドである。
lst.sort()
lst
[0, 1, 3, 4, 9, 100]
オブジェクトのメソッドを調べる場合,dir()
の出力は見にくいので,py4macro
モジュールに含まれるsee()
関数を使うのがおすすめである(モジュールについては次のセクションを参照)。もちろん,Pythonやモジュールの説明書(docs)をチェックするのも必要である。
if
文#
if
文を説明する前にprint()
関数について触れておく。Python
を起動すると,多くの関数が使える状態になる。その一つがprint()
関数であり,値を表示することができる。
pi = 3.14
print(pi)
3.14
コンマ,
を使うと複数の値を表示することができる。
print(pi, 'は円周率です。')
3.14 は円周率です。
if
文を使うと,あるブール型(真偽)の条件のもとでコードを実行することが可能となる。例えば,x
の値が正の場合,
print(x, 'は正です')
を実行したいとしよう。
x = 10
if x > 0:
print(x, 'は正です。')
else:
print(x, 'は正ではありません。')
10 は正です。
<注意点>
if
とelse
で始まる条件を示す行の最後は:
となる。
print()
の行は4つの半角スペースのインデントを入れること。(半角スペースが入っていれば,スペースの数は関係なしにエラーは発生しない。しかし可読性向上のために4つの半角スペースを使うことが慣例となっている。)
else
とは「X>0
以外の場合」という意味。
ここでelse
以下を省略してもエラーにはならないが,x>0
がFalse
の場合,なにも表示されない。
次に,複数の条件を導入するために次の3つprint
関数を使おう。
print(X, 'は正です')
print(X, 'はゼロです')
print(X, 'は負です')
X
の値が正の場合は1
を,ゼロの場合は2
を,負の場合は3
を表示したいとしよう。
x = -1
if x == 0:
print(x, 'はゼロです。')
elif x > 0:
print(x, 'は正です。')
else:
print(x, 'は負です。')
-1 は負です。
注意点
if
,elif
,else
で始まる条件を示す行の最後は:
となる。print()
の行は4つの半角スペースのインデントが入る。elif
はelse if
の省略形であり,2つ目の条件を定義する。elif
はif
とelse
の間に複数入れることが可能x<0
の条件は不要(残りの可能性はx<0
しかないため)
for
ループ#
for
ループは同じコードを複数回リピートして実行したい場合に有効な方法である。例えば,次のリストにある名前を表示したいとしよう。
name_lst = ['太郎', '次郎', '三郎', '四郎', '五郎']
for name in name_lst:
print(name)
太郎
次郎
三郎
四郎
五郎
説明と注意点
for
がある一行目は:
で終わる。name
はname_lst
にあるそれぞれの要素を割り当てる変数。name
ではなくi
やs
など使いやすい記号を使って構わない。name_lst
にある要素を最初から一つずつ実行する。2行目は4つの半角スペースを使ってインデントしている。
for
ループでよく使うパターンして次の例を考える。この例では,リストに要素を追加する.append()
を使うが,これについては以下でより詳しく説明する。
まず次のリストを定義する。
var_lst = [10, 20, 30, 40, 50]
それぞれの要素の2倍からなるリストを作成したいとしよう。
my_lst = [] # 1
for i in var_lst: # 2
my_lst.append(2*i) # 3
このループの考え方:
空のリストの作成(ここに2倍にした数字を格納する)
ここから
for
ループの始まりとなる。i
はループを回していく際に[10,20,30,40,50]
の各要素を割り当てる変数となる。var_lst
には5つの要素があるので5回同じ作業を繰り返す。1回目のループでは,var_lst
の0
番目の要素10
をi
に割り当てる。次の行に進んで,その行の評価が終わると2回目のループが始まり,var_lst
の1
番目の要素20
をi
に割り当てる。そして次の行に進み,その評価が終わると3
回目のループが始まり,同じ作業が続く。ループは5回目で終わることになる。.append()
は2*i
をmy_lst
に追加するリストのメソッド(関数と同義であり,後ほど違いを説明する)であり,この行が評価される毎にmy_lst
に2*i
が追加されて行くことになる。
このように,for
ループとは上のコードの2〜3を5回繰り返している。my_lst
を表示しよう。
print(my_lst)
[20, 40, 60, 80, 100]
Note
上の例ではfor
ループの1行目にリストを使って(name_lst
やvar_lst
),0
番目の要素から順に関数・メソッドを使った。これはリストが要素を1つずつ返すことができる反復可能なものであり,**iterableと呼ばれ,タプルや文字列,そして後で説明する
Numpyの
array`も含まれる。
次の例では文字列を一文字ずつ表示する。
my_str = 'Kobe' # 文字列を作成しmy_strに割り当てる
for s in my_str: # forループの開始
print(s) # 文字を表示
K
o
b
e
基本的な考え方:
1
回目のループでK
がs
に割り当てられ,K
が表示される。2
回目のループでo
がs
に割り当てられ,o
が表示される。3
回目のループでb
がs
に割り当てられ,b
が表示される。4
回目のループでe
がs
に割り当てられ,e
が表示される。
for
ループの中にif
を使う例を考えてみよう。偶数を10倍にし,奇数を1/10にしている。
my_lst = [] # 空のリストの作成
for i in var_lst: # forループの開始
if i % 2 ==0: # 余りが0の場合
x = 10*i # 10倍にしてxに割り当てる
else: # 余りが0でない場合
x = i/10 # 10分の1にしてxに割り当てる
my_lst.append(x) # xをmy_lstに追加
print(my_lst) # my_lstの表示
[100, 200, 300, 400, 500]
内包表記#
リストの内包表記(list comprehension)とはforループの考えを使い、リストを簡単に1行で生成する方法である。次の構文となる。
[<実行したい内容> for <要素を割り当てる変数> in <イタラブル>]
for <要素を割り当てる変数> in <イタラブル>
はforループの1行目と同じとなる。<イタラブル>はリストやタプルなどを指す。
<要素を割り当てる変数>には
i
や_
などを使う。:
は入らない。<実行したい内容>の箇所でループで実行したいコードを書く。
for
ループと比べて例を考える方が分かりやすいだろう。
lst = []
for i in range(5):
lst.append(i**2)
lst
[0, 1, 4, 9, 16]
このコードは0
から4
までの整数を2乗したリストを作成している。内包表記を使うと1行で書ける。
lst_lc = [i**2 for i in range(5)]
lst_lc
[0, 1, 4, 9, 16]
forループと内包表記を並べると2つの関係がより分かりやすくなるだろう。
lst = []
for i in range(5): #1
lst.append(i**2)
[
i**2
for i in range(5) #2
]
[0, 1, 4, 9, 16]
#1
と#2
は殆ど同じになっており、違いは:
だけとなる。
パッケージとモジュール#
Pythonには組み込み関数が多く用意されている。例えば,このリンクを参照。しかし組み込み関数には計量経済学用の便利な関数は用意されていない。そこで活躍するのがモジュール(modules)やパッケージ(package)と呼ばれるものである。もちろん計量経済学以外のモジュールやパッケージが無数にあり,使う用途(例えば,グラフを描く)に沿って読み込むことになる。2つの違いを簡単にいうと
モジュールは1つのファイル(.py)にまとめられた関数群であり,
パッケージは複数つのファイル(.py)で構成され,フォルダーにまとめられているもの
となる。従って,モジュール全体を読み込んだり,あるパッケージの1つのモジュールだけを読み込むということも可能である。
まず例としてrandom
モジュールを考える。ランダム変数を生成する関数が含まれるモジュールである。使うためにはimport
を使って読み込む必要がある。
モジュールの全てを読み込むとモジュール内の全ての関数が使用可能となる。
import random
Hint
通常,モジュールやパッケージをインポートする上のようなコードは,ファイルの一番上に書くのが慣例となっているので,それに従うことにしよう。
様々な関数が用意されているが,その中のrandint()
関数は、引数で指定するランダムな整数を返す。
第1引数:最小値(整数型)
第2引数:最大値(整数型)
次のコードは\([0,6]\)の間の整数(サイコロの目)を返す。1
と6
は戻り値に含まれることに注意しよう。
random.randint(1, 6) # randint は random integers (ランダムな整数)の略
2
このコードの「.
」を助詞「の」と読んで,random.randint
の部分を「random
モジュールのrandint
関数」と読むことができる。このコードの先頭にrandom
があるのは、他のパッケージやモジュールに.randint()
関数がある場合、それとバッティングしないようにするためである。
内包表記を使って、10
回サイコロを投げた結果をリストで表示してみよう。
[random.randint(1, 6) for _ in range(10)]
[6, 4, 1, 5, 6, 6, 2, 3, 5, 5]
モジュール名が長い場合は,短い名前で読み込むことも可能である。
import random as rm
「random
モジュールをrm
としてを読み込む」と理解すれば良いだろう。
rm.randint(1, 6)
6
モジュール内の特定の関数だけを読み込むことも可能である。
from random import randint
「random
モジュールからrandint
を読み込む」と理解できる。
randint(1, 6)
6
この読み込み方法の利点はモジュール名を省略できることだが、他のパッケージやモジュールと同じ関数がある場合,後でimport
したものが優先され、意図しない結果になり得るので、この読み込み方法は避けた方が良いだろう。
前のセクションでdir()
を使いオブジェクトの属性を調べたが,py4macro
モジュールのsee()
関数を使うと属性・メソッドのリストが見やすく。それを使ってみよう。まず,モジュールをインポートする。
import py4macro
see()
関数を使ってみよう。
moji = '神戸大学、良いとこ、一度はおいで🎵'
py4macro.see(moji)
.capitalize .casefold .center .count
.encode .endswith .expandtabs .find
.format .format_map .index .isalnum
.isalpha .isascii .isdecimal .isdigit
.isidentifier .islower .isnumeric .isprintable
.isspace .istitle .isupper .join
.ljust .lower .lstrip .maketrans
.partition .removeprefix .removesuffix .replace
.rfind .rindex .rjust .rpartition
.rsplit .rstrip .split .splitlines
.startswith .strip .swapcase .title
.translate .upper .zfill
py4macro.see
は「py4macro
モジュールのsee
関数」と読むことができる。see()
関数を使うと,ダンダー・メソッドは省略され,見やすくなっている。
Note
py4macro
モジュールはAnacondaに含まれていないので,TerminalもしくはGit Bashで以下を実行して事前にインストールする必要がある。
$ pip install py4macro
エラー#
エラー(Errors)は以下の2つに分けられる。
構文エラー(Syntax Errors)
構文自体が間違っている場合に発生するエラー(例えば,スペル間違い)。
例外(Exceptoins)
構文は間違っていなくてもコードの実行中に発生するエラー(例えば,数字を
0
で割る)
<<コメント>>
エラーが発生するとエラー・メッセージが表示されるが,多くの場合,エラー・メッセージにエラーの理由のヒントがあるので確認することを強く推奨する。はじめは意味が分からないかも知れないが,パターンがあるので慣れると直ぐに理解できるケースも多くあるだろう。
例外の場合,最初にエラーが発生するとそれに付随して他の場所でもエラーが誘発される場合がある。
Python
はエラーを追跡し,最後に確認したエラーをメッセージの一番最後に表示する。最初は、一番最後のエラー・メッセージを確認しよう!
構文エラー#
例1#
(正)print
(誤)primt
primt('hello')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[145], line 1
----> 1 primt('hello')
NameError: name 'primt' is not defined
矢印(—->)でエラー箇所が示されている。
NameError
として最終行にスペル間違いであるprimt
が示されている。name 'primt' is not defined
とは「primt
という名前(変数のこと)は上で定義されていない」という意味。
例2#
for
ループの最初の行の終わりに:
が抜けている。
a = 3
for i in range(0,3)
print(i)
Cell In[146], line 3
for i in range(0,3)
^
SyntaxError: expected ':'
line 3
はセル内の3行目を示している。SyntaxError
として最後の行で:
が足りない箇所を^
で指し示している。expected ':'
とは「:
があるはず」という意味。
例3#
最後の括弧を閉じていない。
(2.1 + 1.5) / (10.0 + 1.0 + 3.2
Cell In[147], line 1
(2.1 + 1.5) / (10.0 + 1.0 + 3.2
^
SyntaxError: incomplete input
この場合,Python
はプログラマーがどこに)
を入れようとしたかは分からない。従って,最後に)
が入ると想定して^
を文末に置いている。
incomplete input
とは「不完全なインプット」という意味。
例外#
例1#
0
が分母にある。
2.0 + 1/0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[148], line 1
----> 1 2.0 + 1/0
ZeroDivisionError: division by zero
division by zero
とは「0
で除している」という意味。
例2#
定義されていない変数xx
が使われている。
10 + xx * 2
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[149], line 1
----> 1 10 + xx * 2
NameError: name 'xx' is not defined
name 'xx' is not defined
とは「xx
という名前(変数)は上で定義されていない」という意味。
例3#
文字列とfloatを足している。
'3' + 10
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[150], line 1
----> 1 '3' + 10
TypeError: can only concatenate str (not "int") to str
can only concatenate str (not "int") to str
とは「文字列型と文字列型のみを連結することができる(文字列型と整数型は不可)」という意味。
ヘルプ#
組み込み関数であるhelp()
を使うと関数やモジュールなどのDocstring
と呼ばれる説明を表示させることができる。例えば,print()
を例として挙げる。
help(print)
Help on built-in function print in module builtins:
print(*args, sep=' ', end='\n', file=None, flush=False)
Prints the values to a stream, or to sys.stdout by default.
sep
string inserted between values, default a space.
end
string appended after the last value, default a newline.
file
a file-like object (stream); defaults to the current sys.stdout.
flush
whether to forcibly flush the stream.
<注意>
help()
関数の引数は関数名であり()
は付いていない。()
を付けるとprint()
を評価した結果に対しての説明が表示されることになる。
英語の説明しかないが、パターンを理解すればこれだけでも有用に感じることだろう。
help()
の代わりに?
を使うこともできる。
print?
ヒントと注意点#
ヒント1#
()
の場合,改行しても構わない。一行が長くなる場合,(
と)
の間で改行することができる。
(10, 20, 30,
40, 50, 50)
(10, 20, 30, 40, 50, 50)
ヒント2#
文字列を改行する場合は次の例のように\
を使う。
'神戸大学\
経済学部'
'神戸大学経済学部'
注意点:スコープ#
スコープとは、変数が所属し直接アクセスできるコードの中の「領域」を示す。類似する概念に名前空(Namespace)もあるが、スコープ(Scope)と同義と理解すれば良い。
ここでは基本的に以下のように理解すれば良いであろう。
Jupyter Notebookを開始した時点からglobalスコープが始まる。
関数を定義すると、その関数の範囲内でlocalスコープが生成される。
globalスコープで定義された変数は、localスコープからアクセスできるが、globalスコープからlocalスコープの変数にはアクセスできない。
関数を実行すると次の順番で変数を探す。
関数のローカス・スコープ
グローバル・スコープ
次の例を考えよう。
s = "Kobe Univ" # globalスコープ
def scope_0():
s = "神戸大学" # localスコープ
return s
scope_0()
'神戸大学'
この関数を実行すると、Pythonはまず関数scope_0
のローカル・スコープ内で変数s
を探すことになる。ローカル・スコープにs
があるので、それを返している。次の関数を考えよう。
def scope_1():
return s
scope_1()
'Kobe Univ'
この例では、まずPython
はローカル・スコープにs
があるかを確かめる。ローカル・スコープにないため、次にグローバル・スコープにs
がないかを確かめている。グローバル・スコープにs
があったので、それを返している(ないとエラーが出る)。
次の例では、グローバル・スコープからローカル・スコープの変数へのアクセスを考える。
def scope_2():
s_local = 'Pythonは楽しい(^o^)/'
return s_local
scope_2()
'Pythonは楽しい(^o^)/'
s_local
は関数scope_2
のローカル・スコープで定義されている。グローバル・スコープからアクセスしようとするとエラーが発生する。
s_local
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[158], line 1
----> 1 s_local
NameError: name 's_local' is not defined