今回もPythonの基礎の続きです。
前回はこちら
[100日後にエンジニアになるキミ - 31日目 - Python - Python演習2]
(https://qiita.com/otupy/items/8b7436e4df68c6c94fb1)
関数
少し前に組み込み関数についてやっていますが今回は関数についてです。
組み込み関数はPython言語に初めから備わっている機能になりますが
関数は自分で定義することができます。
関数の定義の仕方
def 関数名(引数):
return 戻り値
関数に関係する用語ですが、まずは引数があります。
関数の()かっこの中に書くことができます。
引数は関数の中で使えるデータを受け渡す際に用います。
次に戻り値ですが、関数の中で計算された結果を
関数の外に戻す際に用います。
早速関数を定義して見ましょう。
# 関数の定義
def abc(aaa=0):
print(aaa)
return 1
# 関数の実行
print(abc())
print(abc(2))
0
1
2
1
引数の変数名の後に=イコールをつけて値を代入しておくと、
引数が指定されなかった場合に、初期値として使われる値になります。
戻り値は関数の実行結果なので
変数に格納したりする事もできます。
# 関数の実行結果が変数に格納される
a = abc(3)
print(a)
3
1
戻り値や引数は設定しなくても関数として定義できます
def defg():
print('dd')
defg()
dd
特に値を戻す必要がなければ
return無しで戻り値をなくしても大丈夫です。
関数の結果を用いて次に処理を行いたい場合は
returnを付けて値を戻すようにします。
引数は何個でもつけることができますが、
あまり多すぎると使うときに困ると思います。
なので5-6個くらいに納めた方が良いかと思います。
それ以上になるようであれば処理を改めたほうが良いでしょう。
関数を定義するときに引数を定義したら、
使うときもその引数の分だけ指定することが必要になりますが、
関数によっては引数で処理を変えたりしたいというニーズもあったりします。
そんな時は引数に**をつけると
引数をタプル型や辞書型で受け取ることができます。
def aaa1(**karg):
print(karg)
# 関数の引数に辞書型を渡す
aaa1(aws=[1,2])
{'aws': [1, 2]}
複数の引数にまとめてデータを渡せます。
def aaa2(arg1, arg2, arg3):
print(arg1)
print(arg2)
print(arg3)
lis = ['one', 'two', 'three']
# 関数の実行にリストをタプル型にして渡す。
aaa2(*lis)
one
two
three
ただしこの場合は引数の数と合わなければなりません。
個数が合わないとエラーが発生します。
lis2 = ['one', 'two', 'three','four']
# 引数の数と渡す数が合わ無いとエラーになる。
aaa2(*lis2)
TypeError: aaa2() takes 3 positional arguments but 4 were given
関数の使い方としては、複数行にまたがる処理が
2回以上行われる場合は、関数化していった方が
コードがスッキリして見やすく、メンテナンスもしやすくなります。
同じような処理を2度書くくらいであれば、全体を見直して
簡略化、省力化ができる部分を書き直してゆく、という感じで
関数を作っていくのが良いと思います。
特定の関数は別名でメソッドとも読んでいます。
プログラミングでは必須になる概念のため必ず覚えておいてください。
global変数とスコープ
関数などを使う際に必ず付いてくるのが、スコープという概念です。
これは宣言した変数が使える範囲を示す概念のことです。
スコープにはグローバルとローカルの2種類があります。
ざっくり説明すると、一番外にあるものがグローバル
関数のブロックの中がローカルということになります。
ではその違いについて見て見ましょう。
まずはグローバルで使える変数を用意します。
global_var = 'global'
次に関数を定義して、その中で使える変数を用意します。
def local_def():
# ローカル用の変数
local_var = 'local'
return local_var
両方の変数を呼び出してみましょう。
グローバル変数の呼び出しは
print(global_var)
global
ローカル変数の呼び出しは
print(local_var)
NameError Traceback (most recent call last)
in ()
----> 1 print(local_var)
NameError: name 'local_var' is not defined
変数が定義されていないと、エラーが出てしまいます。
ローカルで定義したものは、
そのローカルのブロックの中でしか使えないからです。
なのでこのlocal変数が使えるのは、
定義した関数の中だけになります。
次に関数をいじって、グローバル変数を関数の中で読んでみましょう。
def local_def():
# グローバル変数の参照
print(global_var)
local_def()
global
グローバルで宣言した変数はどこでも使用することができます。
ローカルで宣言したものを
グローバルで使うにはどうすればいいでしょうか?
関数であれば戻り値として
グローバルの方に戻すことで使い回すことができます。
def local_def():
local_var = 'local'
# ローカルで定義した変数を戻す
return local_var
g2 = local_def()
print(g2)
local
for文の方も見て見ましょう。
global_var = 'g'
for i in range(5):
j = global_var*i
# ローカルの変数をそのままプリントする
print(i,j)```
4 gggg
結果は最終的に代入された結果のみが反映されることになります。
`for`文のブロックで使用していた`変数`などを
気づかずに再利用してしまうケースなどがありえると思いますが、
`変数`に格納した値によってはプログラムの結果に大きく影響が出てきます。
最後に、`グローバル`と`ローカル`で変数名がかぶってしまった場合どうなるでしょうか?
```python
sp = 'global'
def local_def():
sp = 'local'
print(sp)
local_def()
print(sp)
local
global
一旦ローカルで同じ変数名で定義していますが
関数を呼び出した際はその関数で定義した変数名で
上書きされる形になるのでローカルで代入した値が表示されます。
その後グローバルの変数を呼び出す際には
元の値が表示されるという仕組みです。
globalという予約語を用いると、
このグローバル変数をローカル側で操作することできます。
sp = 'global'
def local_def():
# ローカルでグローバル変数として定義
global sp
sp= 'local'
print(sp)
local_def()
print(sp)
local
local
一旦ローカルで変数の前にglobalをつけて宣言し、
その後に変数に代入するとグローバルの変数の操作をすることができます。
グローバルとローカルで同じ変数を用いると、
不慮のバグの元になりやすいです。
なので慣れないうちは変数名はなるべく被らないような
名称にすることをお勧めします。
無名関数
さてこれまでは関数についての授業を行ってきましたが、
今回は無名関数というものについてのお話です。
ソートの回で少しだけ触れた
lambdaラムダというものについてです。
ラムダ式とも呼び、名前のない関数を作ることができます。
ラムダ式の書き方
lambda 引数 : 処理
普通の関数の書き方だと
def add (a,b):
return a+b
print(add(2,3))
5
このようになりますが
ラムダを使った無名関数だと
add = lambda a,b : a+b
print(add(2,3))
5
ラムダの後に書いた変数を受け取って:の後の処理が実行されます。
ラムダ式で変数addに関数を代入し
その変数を用いると関数が実行される仕組みです
通常の関数との違いはほとんどなく関数を定義したほうが無難です。
ラムダ式が効力を発揮するのはsortなどの時です。
辞書型の値でソートの際にこのラムダ式が出てきました。
dct ={ 3:7 , 5:6 ,1:3 }
# 辞書型を値で昇順ソートする。
print(sorted(dct.items(), key=lambda x:x[1]))
[(1, 3), (5, 6), (3, 7)]
key= 以降がラムダ式です。
sorted関数の引数keyが関数を受け取れます。
複雑なソートをする場合にラムダ式が役立ちます。
lis1 = [2,3,4,5,7]
# 要素を3で割った余りでソートするような場合
print(sorted(lis1 , key=lambda x:x%3))
[3, 4, 7, 2, 5]
辞書型の際はキーと値をタプル型で返してきます。
dct ={ 3:7 , 5:6 ,1:3 }
print(sorted(dct.items(), key=lambda x:x[1]))
[(1, 3), (5, 6), (3, 7)]
key=lambda x:x[1] のインデックス部分で
[0]がキー、[1] が値となります。
値でソートしたいのなら、
ラムダ式ではインデックスの二つ目すなわち1となるので
key=lambda x:x[1]と指定することになるのです。
これは複合したデータの並び替えなどで役立つことになります。
# 多重のリストを定義
complex_list = [[1,2,3],[3,5,2],[2,6,8]]
print(complex_list)
[[1, 2, 3], [3, 5, 2], [2, 6, 8]]
# リストの最初の値で並び替え
print(sorted(complex_list,key=lambda x : x[0]))
# リストの2番目の値で並び替え
print(sorted(complex_list,key=lambda x : x[1]))
# リストの3番目の値で並び替え
print(sorted(complex_list,key=lambda x : x[2]))
[[1, 2, 3], [2, 6, 8], [3, 5, 2]]
[[1, 2, 3], [3, 5, 2], [2, 6, 8]]
[[3, 5, 2], [1, 2, 3], [2, 6, 8]]
大きなリストの要素として存在するリストの並べ替えのキーを
リストの各項目で定義することができます。
このようにすればどのようなデータの形でも対応できるようになるので
ラムダ式が大活躍します。
関数を定義するまでもないような小さな処理に向いていますので
関数やソートでの利用の仕方を覚えておきましょう。
まとめ
関数は処理を簡略化させたり、まとめたりするのに非常に役立つ機能です。
関数の定義の仕方と、スコープでの変数の取り扱いが
どう働くのかをしっかり押さえておき、バグが起きないように心がけよう。
君がエンジニアになるまであと68日
作者の情報
乙pyのHP:
http://www.otupy.net/
Youtube:
https://www.youtube.com/channel/UCaT7xpeq8n1G_HcJKKSOXMw
Twitter:
https://twitter.com/otupython


