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 (ランダムな整数)の略
4
このコードの「.」を助詞「の」と読んで,random.randintの部分を「randomモジュールのrandint関数」と読むことができる。このコードの先頭にrandomがあるのは、他のパッケージやモジュールに.randint()関数がある場合、それとバッティングしないようにするためである。
内包表記を使って、10回サイコロを投げた結果をリストで表示してみよう。
[random.randint(1, 6) for _ in range(10)]
[1, 3, 1, 2, 6, 2, 3, 2, 3, 3]
モジュール名が長い場合は,短い名前で読み込むことも可能である。
import random as rm
「randomモジュールをrmとしてを読み込む」と理解すれば良いだろう。
rm.randint(1, 6)
4
モジュール内の特定の関数だけを読み込むことも可能である。
from random import randint
「randomモジュールからrandintを読み込む」と理解できる。
randint(1, 6)
2
この読み込み方法の利点はモジュール名を省略できることだが、他のパッケージやモジュールと同じ関数がある場合,後で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