pythonで関数を作る時のティップス

#はじめに
pythonの基礎として,ユーザー定義関数について記載していきます。

#ユーザー定義関数とは

関数は大きく分けて２つあります。

組み込み関数：もともとPythonに搭載されている関数
ユーザー定義関数：def構文などを使って自分で定義する関数

#やってみる

defで関数を定義することができます

```python
>>>def 関数名():
...    処理１
...    処理２
```

例えば
以下のように定義し、呼び出すことができます

```python
>>> def add(x,y):
...     print(x+y)
... 
>>> add(100,200)
300
```

```python
>>> def aisatsu():
...     print("こんにちは")
... 
>>> aisatsu()
こんにちは
```

とても簡単に定義することができます。

関数は以下のように分類できます。
・引数のない関数
・引数のある関数
・戻り値がある関数
・戻り値がない関数

これで言うとaisatsu関数は、`引数のない関数であり、戻り値のない関数`です。

以下にある関数は`引数のある関数であり、戻り値がある関数`になります

```python
>>> def add2(x,y):
...     ans = x+y
...     return(ans)
... 
>>> add2(100,200)
300
```
###ところで`戻り値`とは

関数の中の処理が引数を使って行われた後に返ってくる値を戻り値のことで、returnで戻り値を表示することができます。True、Falseといった真偽も返すことができます。
戻り値は、再利用したい値があるときに使用するので再利用の予定がなければ値を返すreturnは必要ありません。つまりprint()で大丈夫です。



#何ができるのか

for文など入れることで、自由にいろんなことができます

```python
>>> def repeat_msg(word, repeat=3):
...     for i in range(1,repeat):
...             print(word+"を"+ str(i)+ "杯目")
... 
>>> repeat_msg("米", repeat=5)
米を1杯目
米を2杯目
米を3杯目
米を4杯目
>>> repeat_msg("米")
米を1杯目
米を2杯目
>>> 
```

後述しますが、repeat=3とデフォルト値を入れているので、repeatを指定しない場合には、デフォルト値が使われる。


こんなこともできます。
\*name は残りの順序引数を、**names はキーワード引数を辞書型で受け取ります。

```python
>>> def func(a1, a2, *name, **names):
...     print(a1)
...     print(a2)
...     print(name)
...     print(names)
... 
>>> func("A","B","C","D",k1="k1",k2="k2")
A
B
('C', 'D')
{'k1': 'k1', 'k2': 'k2'}
```

上記のようなkwarg=valueという形式をキーワード引数と呼びます。
キーワード引数は位置引数の後でなければなりませんが、順序は特に重要ではありません。ただし複数回は受け取ることはできません。

```python
>>> def kansu_test(word, kw1='b', kw2='c', kw3='d'):
...     print(word)
...     print(word,kw1)
...     print(word,kw3)
...     print(word,kw3,kw1)
... 
>>> kansu_test("a")
a
a b
a d
a d b
>>> kansu_test("a",kw3="abc")
a
a b
a abc
a abc b
```


#デフォルト値
引数には、デフォルト値を設定することができます。
関数は引数を指定しなくても実行することができ,その場合にはデフォルト値が有効になります。

```python
>>> def wakariyasui_kansu(arg1, arg2 = "引数なし"):
...     print("arg1:" + arg1 + " arg2:" + arg2)
... 
>>> wakariyasui_kansu("引数1")
arg1:引数1 arg2:引数なし
>>> wakariyasui_kansu("引数1","引数2")
arg1:引数1 arg2:引数2
```
他にも税率計算で5%の軽減税率を指定することができます。(使うことはない)

```python
>>> def keisan_kansu(x, y = 1.08):
...     price = x * y
...     return(price)
... 
>>> keisan_kansu(100)
108.0
>>> keisan_kansu(100,1.05)
105.0
>>> 
```


#補足:グローバル変数(global)
関数の外部で定義された変数は`グローバル変数`として扱われます。
関数を実行するとき、関数のローカル変数のために使われる新たなシンボルテーブルが用意されます。
関数内で変数への代入を行うと、その値はすべてこのローカルなシンボルテーブルに記憶されます。
一方、変数の参照を行うと
①ローカルなシンボルテーブルが検索される
②さらに外側の関数のローカルなシンボルテーブルが検索される
③グローバルなシンボルテーブルが検索される
④最後に組み込みの名前テーブルが検索される
つまり関数の中でグローバル変数を参照することしかできず、代入はできません。
もし代入を行う場合には、global宣言をする必要があります。

```python
>>> count = 0
>>> def func():
...     count = 2
... 
>>> func()
>>> count
0
```
グローバル変数は代入されていません。
以下のようにグローバル宣言をすることで代入ができます。

```python
>>> def func():
...     global count
...     count = 2
... 
>>> func()
>>> count
2
```

なおグローバル変数/ローカル変数は、以下のように取得するとができる

```python
>>> def func():
...     for k in globals().keys():
...             print("GLOBAL: %s = %s" % (k, globals()[k]))
...     for k in locals().keys():
...             print("LOCAL: %s = %s" % (k, locals()[k]))
... 
>>> func()
```

#ラムダ式(lambda)
ラムダ式(lambda)式は、defよりも小さい関数を定義します。
ラムダ式自体は式として扱われるため、関数の引数に指定することができます。

```python
>>> func = lambda x, y: x + y
>>> print(func(3, 5))
8
```
sorted(), map(), filter()などの関数に渡す無名関数として利用されることがあります。

```Python
>>> a = [1, 2, 3]
>>> print(list(map(lambda x:x**2,a)))
[1, 4, 9]
```

>map()を使うと、Python2系ではリストを返してきますが、Python3系ではリストではなく`iterator object`を返すように挙動が変更されています。
iteratorを返すことで、全要素を計算せず、要素が必要とされる時に計算するようになり、使用するメモリ量を低く抑えているとのこと。

と言うことでlist()をつけています。

#おまけ：printとreturnの違い

覚えておく必要があるのは
・returnは値を返すだけ
・printはコンソール上に表示するだけ
という違いです。

つまりreturnを使うのはその戻り値を再利用する為です。
以下は
world()で、hello()の戻り値である"hello"を再利用しています。

```python
>>> def hello():
...     return 'hello'
... 
>>> def world():
...     a = hello()
...     return(a + ' world')
... 
>>> print(world())
hello world
```
#参考
[[Python]常識ですよ？と言われないための引数入門](http://note.crohaco.net/2014/python-argument-intro/)

https://note.nkmk.me/python-if-name-main/


#おわり