関数

1.関数の基本

(1)関数について

関数はあらかじめ作成されているものもあれば、自分で作ることもできる。
len() や sum() なども事前に組み込まれた関数で、たとえば、引数を関数に渡すと、値を返してくれる。
関数を使うことで、毎回処理を書く必要がないので、楽である。

あらかじめ作成されている関数は以下に記載がある。
https://docs.python.jp/3/library/functions.html

先に紹介したtypeもその一例
>>> a=2
>>> print(type(a))

(2)関数の作成

・def 関数名:
 処理

【注意点】
・defはdefine(定義する)の意味
・小文字のアルファベットで作ろう。先頭に数字はダメだったはず。
・スクリプト言語なので、上から順に実行される。関数の順番にも注意が必要

単純な例を作ります。helloという関数を作り、hello()で呼ぶ。ただこれだけ。

❶関数を使わない場合
以下はLinux上で実行している。単にprintしているだけ。
・hello.pyのソースコード

#!/usr/bin/python
print('hello')

・実行結果

# ./hello.py
hello

❷関数を作ってみる
・ソースコード (Linux類は抜いた)

def hello():
 print("Hello!!")

・実行結果

# ./hello2.py

このように何も表示されない。というのも、関数hell()を定義しただけで、その関数を実行していないからだ。
では実行するにはどうすればいいか。以下のように、hello()関数を呼ぶ。
・ソースコード

def hello():
 print("Hello!!")

hello()

・実行結果

# ./hello2.py
Hello!!
(3)引数を渡す

・プログラムを処理するときは、入力データがあって、それを演算して結果を出すということが多い。そのために、引数を渡すことができる。先ほどの引数は、引数がなかったので()としてあった。
・引数の渡し方
位置引数とキーワード引数の2つがある。位置は文字通り、場所が対応する。
キーワードも文字通り、value=などと引数のキーワードを指定する
・以下は、aとbの積を求めるsekiという関数を作った。そして、print(seki(3,4))にて、3と4という引数を渡し。戻って来た結果(return)をprintしている。

#!/usr/bin/python
def seki(a,b):
 return a * b

print(seki(3,4))

・引数をaやbに渡しているが、名前は何でもいい。name_bなどと長い文字でもいい
・戻り値をreturnで返せる。※returnの後の処理は実行されない。
・ return a * b のところは、 c = a * b として、 return cとしてもいい。
・細かい話だが、a*bとスペースを入れなくてもいい。

❶例として、値を入力し、その値の2倍を返すプログラムを作る
・bai.pyというプログラム

#!/usr/bin/python
# -*- coding: utf-8 -*-
def bai(x):        #これが関数
 y=x*2
 return y         #2倍にして返り値をyとして返す

print("数字を入力してください")     #画面に表示
x=int(input())             #入力された文字をxに入れる。intにしておかないと、文字列として扱われてしまう
z=bai(x)       
print(z)        #として受け取った返り値を表示する

実行結果として、5を入力した場合、2倍になって10と表示されている。

# ./bai.py
数字を入力してください
5
10

❷pass
何も処理しない場合はpassを使う。何も処理しない。関数をprintしてみると、Noneが返ってくる。

def fun():
    pass
fun()  # →何も表示されない
print(fun())  # →Noneが表示される。

❸引数を指定する
最後の行にあるように、引数の項目を指定すれば、順序が逆になっても可能

def func(name,age):
 print(name,'is',age)
func('Ito',23) #==>Ito is 23
func(age=21,name='Kato') #==> Kato is 21

また、必要な数の引数を受け取らないと、エラーになる。

(4)可変個の引数を渡す

本来、必要な引数の数だけ渡す必要があるが、引数がいくつか不明な場合もある。
以下は2つ目が引数の数が合わないと怒られる。

def func1(i):
    print(i)
func1('aaa')
func1('123', '456')

そのときは、アスタリスク(*)を使うことができる。結果はタプルで返される。
❶可変個の引数

def func(*arg):
 print(arg)
func('abc') #==>('abc',)
func('abc','de') #==>('abc', 'de')
func('abc','de','f') #==> ('abc', 'de', 'f')

❷通常の引数と組み合わせることも可能

def func(x,*arg):
 print(x,arg)
func('abc') #==>abc ()
func('abc','de') #==>abc ('de',)
func('abc','de','f') #==>abc ('de', 'f')

ただ、上記のように、タプルで返してくるので、出力は工夫した方がいいかも。たとえば、以下。

def func(x,*arg):
    print(x, *arg) #==>abc,de,f
    print(x, *arg, sep=",") #==>abc de f
func('abc','de','f') 

❸辞書の場合
アスタリスク(*)を2つ付ける。
辞書型なので、引数を指定するには、key=valueの形にで書く

def func(**arg):
 print(arg)
func(x=1,y=2,z='abc') #==>{'x': 1, 'y': 2, 'z': 'abc'}
(5)引数の初期値

初期値を入れる例をみてみよう。関数funcを2回実行していて、1つは値を渡す場合、2つ目は値を渡さないので、初期値が反映される。

i = 'Hello'

def func(x=i):
  print(x)

func('Ya!') #==>Ya!
func() #==> Hello

2.応用

(1)グローバル変数

関数で定義される変数は、関数の中だけで利用されるローカル関数。
あまりないと思うが、関数内でグローバル変数を宣言したい場合は、global を使う

(2)リストの引数、辞書型の引数

リスト型の引数を渡す場合は*をつける
辞書型の   〃    **  〃

(3)リストの引数、辞書型の引数

リスト型の引数を渡す場合は*をつける
辞書型の   〃    **  〃

3.関数のモジュール化とパッケージ化

(1)関数のモジュール化

まずはやってみよう
必要な関数は部品として別ファイルにしておくと便利だ
実際に作ってみよう。以下のm1.pyは、受け取った値を2倍にして返す関数
・m1.py

def bai(x):
    return x*2

・メインの関数。つまり実行するファイルは以下のpg1.py

import m1 #m1.pyというファイルをimport
print(m1.bai(3)) #m1のbaiという関数を実行する

→結果は6と表示される。

(2) if __name__ == '__main__': について

❶概要
・__name__は、定義しなくても最初から存在している変数である。
・__name__には、実行しているモジュールの名が入る。
・プログラムが書かれているファイルで実行した場合、自動で__main__が入ります。
・他のプログラムから呼ばれたモジュールの場合、そのモジュールの名が入ります。たとえば、mod1.pyのモジュールを呼んだ場合、mod1が入る。

❷順番に実施していこう

print(__name__)

結果は以下

__main__

つまり、__name__という変数には__main__という値が入っている。

❸if __name__ == '__main__':の意味
__が入っているからわかりにくいが、単に、変数__name__ が入っていると考えるといいだろう。
つまり、自分のモジュールの場合だったら、ということだ。他のモジュールから呼ばれた場合には実行しない。
自分のプログラムか他から呼ばれたのかを判断するための仕組み。
なので、以下の2つプログラムpg1.pyを実行すると、同じ結果を表す

print('hello')

・こちらは、ifからの内容を入れた場合

if __name__ == '__main__':
    print('hello')

➍モジュールを呼んでみよう
たとえば、以下のm1.pyというファイル(プログラム)がある。
・直接実行する場合

if __name__ == '__main__':
    print("Hello")
def bai(x):
    return x*2

これをこのまま実行すると、実行している自分自身だから、変数__name__ には__main__が入っている。よって、printが実行されて結果は以下

Hello

・モジュールを呼び出して実行する場合
pg1.pyからm1.pyというファイルを呼び出す

import m1
print(m1.bai(3))

すると、関数baiだけが実行されて、printは実行されない。

6

以下は続き
qiita.com

(3)モジュールのインストール

・以下のようにしてインストールする

pip install janome
pip3 install janome

インストールされているリストを表示

pip list
(4)標準モジュール

❶sysモジュール
・インタプリンタにビルトインされているモジュール
・import sys を使う。
以下、ps1とps2には、標準プロンプトが入っている。これを変更すると、以下のようにCisco
スイッチのようなプロンプトに変更することもできる。

>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1='Switch> '
Switch>

❷dir()関数
sysがどんなモジュールを定義しているのかを確認するために、dir()を使う。先ほど使ったps1やps2も見つけることができた。

>>> dir(sys)
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__', '_base_executable', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_framework', '_getframe', '_git', '_home', '_xoptions', 'addaudithook', 'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix', 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'getallocatedblocks', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'platlibdir', 'prefix', 'ps1', 'ps2', 'pycache_prefix', 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info', 'warnoptions', 'winver']
>>>
(5)パッケージ

パッケージ (package) は、ドットを付けてモジュールを構造化(まあ、階層化と思ってもいいだろう)する。

(6)関数その他

・関数アノテーション
Annotation(注釈)のこと