こんにちは(@t_kun_kamakiri)(‘◇’)ゞ
この記事ではPythonの「関数」について解説します。
- 関数の基本的な書き方
- 関数に引数を使った書き方
- 関数の中に関数を書く(クロージャー)
Pytonの関数は以下の2通りを覚えておきましょう。
- 「def 関数名()」の基本的な書き方
- 「lambda パラメータ1, パラメータ2 : 処理」の書き方
こちらの本がPython初心者が挫折することなく勉強できる本です。
(本記事のようのPython使用環境と異なりますが、とてもわかりやすいので全く問題ありません)
Pythonの関数とは
Pythonの関数は「色々な機能がひとつにまとまったもの」を意味します。
機能とは「したい処理内容」のことを意味しています。
例えば、部屋の温度を下げるため冷房を効かせたいとします。
この時に、人がすることは冷房ボタンを押すだけです。
冷房ボタンを押すことにより、冷房が冷風を送るという動作が行われます。
もちろんリモコンボタンはなんでもしてくれる便利道具ではなく、あらかじめ決められた処理内容が冷房機器には設定されていて、ボタンを押すという処理を呼び出す動作をすることで、冷風を送るという処理が行われたということになります。
以下で具体的にコードを書いてみましょう。
Pythonの関数の書式
Pythonの関数の機能を使うには「def」というキーワードと使います。
defはdefineから来ており、「関数をdefineする」という意味です。
関数の書式
1 2 3 4 5 |
def 関数名(): 処理1 処理2 処理3 ・・・ |
※注意点
- defの最後には「:」を忘れないこと。(これはif文でも同じです)
- 処理1、処理2、・・・の前は「tabスペース」を設けること。
Pythonに対応したエディタであれば自動的に「tabスペース」を作ってくれますが、専用でないエディタであれば自分で「tabスペース」を設ける必要があります。
この「tabスペース」のPythonルールはインデントと呼ばれており、プログラミングの記述をわかりやすくするためのルールです。
※インデントがおかしいとエラーになるため必ずインデントは意識するようにしましょう。
Pythonの関数を使ってみよう
仕組みや概念の理解も大事ですが、とりあえず使って慣れることの方がもっと大事です。
実際にコードを書いてみましょう。
1 2 3 4 5 6 |
def cool(): print("冷風を送る") print("涼しいかい?") #関数を呼び出す cool() |
【結果】
1 2 |
冷風を送る 涼しいかい? |
「cool()」という名前の関数を定義して、その中にprint文で「冷風を送る」と「涼しいかい?」と出力する処理を書いています。
しかし、関数を定義しただけでは何も動作はしません。
その後に、「cool()」と書いて関数を呼び出すことで、関数内の処理が行われます。
ここで注意があります。
関数の呼び出しは、関数を定義した後に記述しなければエラーになってしまいます。
例えば、関数の呼び出しと関数の定義の順番を逆にしてみます。
1 2 3 4 5 6 |
#関数を呼び出す cool_1() def cool_1(): print("冷風を送る") print("涼しいかい?") |
【結果】
1 2 3 4 5 6 7 8 9 10 |
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-4-e1a2b0506c57> in <module>() 1 #関数を呼び出す ----> 2 cool_1() 3 4 def cool_1(): 5 print("冷風を送る") NameError: name 'cool_1' is not defined |
上記のようなエラーとなります。
エラー内容は、「’cool_1’」というな名前のオブジェクトが定義されていないとなっています。
関数の中でif文を使う
関数の中の処理は別段特別なことはしているわけではなく、Pythonの文法に従って書いているだけです。
ですので、今まで習ったif文を関数の中で使うこともできます。
1 2 3 4 5 6 7 8 9 10 11 |
temp = 20 def cool(): if temp == 20: print('温度は%d℃です。' % temp) print("涼しいかい?") else: print('温度は20℃ではありません。) #関数を呼び出す cool() |
【結果】
1 2 |
温度は20℃です。 涼しいかい? |
「temp = 20」なので、関数を呼び出した際の「temp == 20」が真となるため、if文内の、
- print(‘温度は%d℃です。’ % temp)
- print(“涼しいかい?”)
この2つの処理が行われました。
※ちなみに、「print(‘温度は%d℃です。’ % temp)」は、%dにtempの変数が入る記述方法です。
このように、文字列中の変換指定子%d
, %s
を書くと、文字列の中に「% temp」の変数の値が%d
に代入されます。
変換指定子は整数が%d
、浮動小数点が%f
、文字列が%s
。詳しくは公式ドキュメント参照に下ください。
関数に引数を入れて処理結果を返す(円の周長さと面積を計算)
1つの引数を設定
変数として半径を入力して、関数の中で円の周長さと面積を計算してもらいましょう。
実際にコードを書いてみましょう。
1 2 3 4 5 6 7 8 9 |
import math def calc(radi): L=2*math.pi*radi area=math.pi*radi**2 return L, area calc(10) |
【結果】
1 |
(62.83185307179586, 314.1592653589793) |
※補足説明
- import mathで円周率「math.pi」を使えるようにしています。
- 関数defにradiを入れると、周長Lと円の面積areaをradiに応じて計算してくれます。
- その結果を「return L, area」とすることで計算したデータを返すということをしてくれます。
ちなみに結果が「(62.83185307179586, 314.1592653589793)」と、()となっているためタプル型として値が返ってきているということになります。
2つ以上の引数を設定
引数には2つ以上設定することもできます。
例えば薄肉円筒の\(\theta\)方向の応力を計算したいとします。
薄肉円筒の\(\theta\)方向の応力は、\(\sigma=\frac{pD}{2t}\)となります。
では、実際にコードを書いてみましょう。
1 2 3 4 5 6 7 8 9 |
#厚み t = 1.2 def calc(dia, press): sigma_theta = (press * dia)/(2.0 * t) return sigma_theta print('応力は{}Paです'.format(round(calc(50, 100),2))) |
【結果】
1 |
応力は2083.33Paです |
関数「calc」を定義して「dia, press」という直径と圧力の2つの引数を設定しています。
あとは、内部の処理で、「sigma_theta = (press * dia)/(2.0 * t) 」としていますが、これは薄肉円筒の\(\theta\)方向の応力\(\sigma=\frac{pD}{4t}\)を計算式ですね。
それをreturn文で値を返すようにしています。
そして、print(‘応力は{}Paです’.format(round(calc(50, 100),2)))で小数点第二位までをprint文の{}内に埋め込むようにして出力して今sう。
以上のような計算式を用意しておくと、強度が1000Pa以上だと不足するという判断をif文で用意しておけば以下のような強度の判断をする処理が可能になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#厚み t = 1.2 def calc(dia, press): sigma_theta = (press * dia)/(2.0 * t) return sigma_theta calc(50, 100) if calc(50, 100) <=1000.0: print('強度に問題ありません。') else: print('強度不足です。') |
【結果】
1 |
強度不足です。 |
「calc(50, 100)」を計算した結果は1041.67で1000より大きいため、if文内の「強度不足です」がprint文で出力されています。
以上のように引数は2つでも3つでも構いません。
今回の場合でも板厚tをさらに引数にして、「直径、圧力、板厚」で強度不足を判断するプログラムを作っても良いでしょう。
関数の引数に可変長パラメータを設定
先ほどまでは、引数の数が決まっている状態でしたが、引数の数を可変にすることができます。
- 可変長パラメータ(タプル型)
- キーと値がセットになった可変長パラメータ(辞書型)
可変長パラメータには、「タプル型」と「辞書型」にして引数を取り扱う設定方法があります。
可変長パラメータ(タプル型)
可変長パラメータを引数にするために「アスタリスク *」を変数の前に付けて引数を設定します。argsは「アーグス」と呼んでいます。
1 2 3 4 |
def func(*args): #処理 func(パラメータ1,パラメータ2,パラメータ3,・・・) |
1 2 3 4 5 |
def n_month(*args): for i in args: print(i + '月') n_month('1','2','3') |
【結果】
1 2 3 |
1月 2月 3月 |
今回、関数の引数として「*args」としましたが、慣習としてそのような変数名にしましたが、任意の変数名でも構いません。
例えば、以下のようにしても同じ結果を得ることができます。
1 2 3 4 5 |
def n_month(*month): for i in month: print(i + '月') n_month('1','2','3') |
大事なのは、関数の中で引数の名前さえ統一していれば良いということです。
上の例では、複数の引数と関数に引き渡しているのですが、その変数はどのような型で関数に引き渡されているのでしょうか。
それを確認するために、print文でtype()を使って引数の型を確認してみましょう。
1 2 3 4 |
def n_month(*args): print(args, type(args)) n_month('1','2','3') |
【結果】
1 |
('1', '2', '3') <class 'tuple'> |
引数の要素がタプル型としてセットになっているのが確認できますね。
また、次のように別の引数を関数に用いることもできます。
1 2 3 4 5 6 7 8 |
def n_month(x, y, *args): print(x, y) print(args, type(args)) x = 10 y = 20 n_month(x, y, '1','2','3') |
【結果】
1 2 |
10 20 ('1', '2', '3') <class 'tuple'> |
ただ、引数の順番を「*args」を前にするとどこまで可変長のパラメータになっているのかわからないためエラーとなります。
1 2 3 4 5 6 7 8 |
def n_month(*args, x, y): print(x, y) print(args, type(args)) x = 10 y = 20 n_month('1','2','3', x, y) |
【結果】
1 2 3 4 5 6 7 8 |
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-12-fbf30ae8816e> in <module> 6 y = 20 7 ----> 8 n_month('1','2','3', x, y) TypeError: n_month() missing 2 required keyword-only arguments: 'x' and 'y' |
しかし、これは関数を呼び出すときの引数を「n_month(‘1′,’2′,’3’, x=10, y=20)」としてやることで、どこまでが可変長パラメータになっているのかがわかるようになり正常に動作します。
1 2 3 4 5 6 7 8 |
def n_month(*args, x, y): print(x, y) print(args, type(args)) # x = 10 # y = 20 n_month('1','2','3', x=10, y=20) |
【結果】
1 2 |
10 20 ('1', '2', '3') <class 'tuple'> |
キーと値がセットになった可変長パラメータ(辞書型)
また、辞書型として引数を設定することもできます。
それには「アスタリスク2つ **」を変数の前に付けて引数を設定します。
kwargsは「クウォーグス」と呼んでいます。
実際にコードを書いてみましょう。
1 2 3 4 |
def n_month(**kwargs): print(kwargs, type(kwargs)) n_month(January='1',February='2',March=3) |
【結果】
1 |
{'January': '1', 'February': '2', 'March': 3} <class 'dict'> |
関数を呼び出すときに、「n_month(January=’1′,February=’2′,March=3)」として引数に「 キー = 値 」という形で変数を引き渡しています。
引き渡す「キー」はデフォルトで文字列になっていますが、「値」については文字列でも数値型でもどちらでも構いません。
上の例でも、「March=3」として引数に渡しているので、「’March’: 3」と値が数値型になって出力されているのが確認できますね。
関数を引数にする
引数にできるのはオブジェクトであるため、オブジェクトである関数も設定することができます。
具体的にコードを書きながら見てみましょう。
1 2 3 4 5 6 7 8 9 10 |
#関数を引数にする def calc(a,b): c = a + b print('2つの足し算は',c) def All_run(func,x,y): func(x,y) All_run(calc, 10, 20) |
【結果】
1 |
2つの足し算は 30 |
何が起こったのかを絵にまとめてみました。
- 最後の行で「All_run(calc, 10, 20)」して「calc 関数」と「10,20 値」を引数として引き渡しています。
- funcには「2つの引数」を渡して処理するということを行います。
このときの。funcは「calc関数」を使えとい指示になっています。 - そして、calc関数に「2つの引数」が渡たします。
今回は2つの引数の値の和を計算する処理を行って、print文で出力するというのを行っています。
先ほどの可変長パラメータを使うと引数の数を変えることもできますね。
1 2 3 4 5 6 7 8 9 10 11 |
#関数を引数にする #引数は可変長パラメータにする def calc(*args): for i in args: print(i) def All_run(func,*args): func(*args) All_run(calc,10,100,1000,10000) |
【結果】
1 2 3 4 |
10 100 1000 10000 |
関数内関数とクロージャー
関数の中に関数を記述する方法についても見ておきましょう。
関数内部で同じような処理を行う場合は重複を避けるために関数にまとめておくのが良いですよね。
関数内関数
実際にコードを書いてみましょう。
1 2 3 4 5 6 7 8 9 |
#関数の中に関数を使う def All_func(a,b): def run_calc(x,y): return x + y return run_calc(a,b) All_func(10, 20) |
【結果】
1 |
30 |
以上のように関数の中に関数を書いて処理をまとめておくことがdけいます。
クロージャー
関数の中に関数を書く方法にクロージャーというのがあります。
変数に関数を格納するとその関数定義自体が格納されることを利用する。
※関数を状態ごと保持したオブジェクト
ちょっとよくわからないかもしれないですね(*_*;
実際にコードを書いてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
#関数の中に関数を使う(クロージャー) def All_func(a,b): def run_calc(): #クロージャー return a + b return run_calc c = All_func(10, 20) print(c) print(c()) |
【結果】
1 2 |
<function All_func.<locals>.run_calc at 0x7f0c1b70c9d8> 30 |
少し理解が難しいかもしれませんが、ひとつひとつ見ていけば良いでしょう。
- 「c = All_func(10, 20)」で引数に「10, 20」を渡しています。
それが「All_func(a,b)」に引き渡されているがわかりますね。 - 「 run_calc()」がクロージャーの部分です。
最後に「return a + b」として引き渡された引数の和を計算して返すようにしています。 - 「return run_calc」で関数のオブジェクトを返すようにしています。
なので、「c = All_func(10, 20)」では関数オブジェクトが生成されているだけになります。
なので「print(‘c’)」では何も出力されず関数オブジェクトのメモリなどが表示されているだけです。
cの中身の処理を行いたい場合は「c()」とすればよいですね。
大事なのはクロージャーは関数のオブジェクトを返すということです。
もうひとつ例を見てみます。
生成したcに引数を渡してやります。
1 2 3 4 5 6 7 8 9 10 11 12 |
#関数の中に関数を使う(クロージャー) def All_func(a,b): def run_calc(add): return a + b + add return run_calc c = All_func(10, 20) print(c) print(c(100)) |
【結果】
1 2 |
<function All_func.<locals>.run_calc at 0x7f0c1b6a48c8> 130 |
cの引数に100を渡しているので、「run_calc(add)」のaddが100になって、「return a + b + add」で処理が行われているということです。
まだ、イメージがつきにくいかもしれませんね。
例えば、先ほど例に出した薄肉円筒の\(\theta\)方向の応力を計算を再度、クロージャーを使って計算してみます。
薄肉円筒の\(\theta\)方向の応力は、\(\sigma=\frac{pD}{4t}\)となります。
すでに、直径と圧力はそれぞれ「直径=50mm」「圧力=100kPa」と決まっているとして、残り板厚をどうするかとなっている状況を想定してみます。
では、実際にコードを書いてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
#関数の中に関数を使う(クロージャー) def All_func(dia,press): def run_calc(t): sigma_theta = (press * dia)/(4.0 * t) return sigma_theta return run_calc sigma_L = All_func(50, 100) print('応力は{}Paです'.format(round(sigma_L(1.2),2))) |
【結果】
1 |
応力は1041.67Paです |
「sigma_L = All_func(50, 100)」では、まだ直径と圧力しか入力しておらず、sigma_L にrun_calc関数のオブジェクトが代入されただけです。
結果を出力するために「sigma_L(1.2)」として引数を渡すことで、run_calc関数内の「return sigma_theta 」が出力されたというわけです。
まとめ
ここまでで、Pythonにおける関数の基本的な内容をお話ししました。
- 関数の基本的な書き方
- 関数に引数を使った書き方
- 関数の中に関数を書く(クロージャー)
まだ、Pythonの関数には学ぶことがあり、例えば、
- ラムダ式:小さな処理を書く
- ジェネレーター:1つずつ取り出す処理(yield関数)
- デコレーター:関数に機能を追加
などは、次回の記事内容としたいと思います。
おすすめ参考書
[…] 【Python初心者】 関数の基本を理解しよう。 […]