今回も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