アフィリエイト広告を利用しています
ファン
検索
<< 2021年01月 >>
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
最新記事
写真ギャラリー
最新コメント
タグクラウド
カテゴリーアーカイブ
月別アーカイブ
プロフィール

広告

この広告は30日以上更新がないブログに表示されております。
新規記事の投稿を行うことで、非表示にすることが可能です。
posted by fanblog

関数の定義





記事内容の出典:フリーテキスト「Python3入門」
このページの更新:2021/01/10

関数とは「ある処理を記述したプログラムの単位」であり

   関数名( 引数の並び )

の形で呼び出します.また,この形で関数を呼び出す(実行する)と,その結果の値を返します.
関数を定義する方法

新たな関数を定義するには次のように def 文で記述します.

   def 関数名( 仮引数1, 仮引数2, … ):
      処理内容
      return 戻り値


このように記述することで「仮引数n」に受け取った値を用いて「処理内容」を実行する関数が「関数名」の名前で定義(作成)されます.この関数を呼び出すと(実行すると)「処理内容」の部分(複数行の記述可)が実行され,最後に「戻り値」を return で返します.

簡単な例として,2つの数の足し算の結果を返す関数 tasu を定義して実行する例を示します.


def tasu(x,y):
return x+y


これで関数 tasu が定義できました.次にこれを呼び出してみます.(次の例)


a = tasu(1,2)
print( a )


実行結果:


3

関数 tasu が計算結果を return によって返している様子がわかります.

■ 引数の呼び名

関数定義を def 文で記述する際に,値の受け取りのために記述する引数を仮引数と言います.また関数を呼び出す(実行する)際に与える引数を実引数と言います.(次の図)

defFunction.gif
(図の出典:フリーテキスト「Python3入門」

■ return の省略

関数定義の最後の return 文を省略することができ,その場合はその関数は値を返しません.(厳密には None を返します)

変数のスコープ

基本的に変数は,関数定義の内部と外部ではそれぞれ別のものとして扱われます.次の例を見てみましょう.


def kansu(x):
v = x*2
print('関数内部のv:',v)


この関数 kansu は仮引数 x に受け取った値を2倍して,関数内部の変数 v に設定します.この後,次のような実行で変数 v の値を確認してみます.


v = 123 # 関数外部の変数vに値を設定
kansu(7) # 関数を実行
print('関数外部のv:',v)


実行結果:


関数内部のv: 14
関数外部のv: 123


関数 kansu の内部の変数 v は外部の v とは別のものであることがわかります.

関数定義の内部でのみ使用される変数をローカル変数と言い,関数定義などの範囲に限定されない変数をグローバル変数と言います.また,このような変数の有効範囲を変数のスコープと言います.

■ 変数のスコープに関する注意すべき点

変数のスコープは関数定義の内外で異なるというのが基本ですが,関数定義の内部でグローバル変数を参照することだけは可能です.次の例を見てください.


def kansu2(x):
print('関数内部から参照するグローバル変数v:',v)
w = x*2
print('関数内部のw:',w)


ここで定義されている関数 kansu2 の内部では,変数 v が参照のみされており,値の設定や変更はされていません.この場合の変数 v はグローバル変数の v です.これを次のプログラムで確認してみます.


v = 123 # 関数外部の変数vに値を設定
kansu2(7) # 関数を実行
print('関数外部のv:',v)


実行結果:


関数内部から参照するグローバル変数v: 123
関数内部のw: 14
関数外部のv: 123


関数 kansu2 の内部でグローバル変数 v の値が参照できていることがわかります.(あくまで参照のみです)

■ 関数定義の内部でグローバル変数を扱う方法

関数定義の内部で明にグローバル変数を扱うには次のように global 宣言します.

   global 変数名

このように関数内部で宣言することで,グローバル変数への値の設定や変更が可能になります.(変数名はコンマで区切って複数記述することができます)

次の例を見てください.


def kansu3(x):
global v
v = x*2
print('関数内部のv:',v)


この関数 kansu3 の内部では変数 v がグローバル宣言されており,値の参照のみならず,値の設定や変更が可能になります.このことを次の例で確認しましょう.


v = 123 # 関数外部の変数vに値を設定
kansu3(7) # 関数を実行
print('関数外部のv:',v)


実行結果:


関数内部のv: 14
関数外部のv: 14


関数 kansu3 の内部でグローバル変数 v の値が変更できていることがわかります.

引数の様々な形態

最も基本的な形としては,関数に渡す引数の個数は固定されたものです.例えば先に定義した関数 tasu は2個の引数を取るもので,これ以外の個数の引数を与えるとエラーとなります.(次の例)


a = tasu(1,2,3)

実行結果:


TypeError Traceback (most recent call last)
〈ipython-input-196-fc2074172be5〉 in ()
----> 1 a = tasu(1,2,3)

TypeError: tasu() takes 2 positional arguments but 3 were given


引数の個数が間違っている旨のエラーが起こっています.

では次に,任意の個数の引数を受け取る方法について説明します.

■ 任意の個数の引数を受け取る関数の定義

def 文で関数を定義する際の仮引数にアスタリスク「*」を付けると,受け取った引数のタプルを取得できます.次の例は,任意の個数の引数を受け取り,それらの合計を求める関数 tasuAll を定義するものです.


def tasuAll( *a ):
s = 0
for n in a:
s += n
return s


定義の際の仮引数を *a としています.これにより,実行時に任意の個数(1個以上)の引数を受け取り,それらを要素とするタプルが a に得られます.様々な個数の実引数を与えて実行する例を下に示します.


print( tasuAll(1) )
print( tasuAll(1,2) )
print( tasuAll(1,2,3) )
print( tasuAll(1,2,3,4) )


実行結果:


1
3
6
10



キーワード引数

Pythonの関数ではキーワード引数と呼ばれる独特な形態の引数を使うことができます.まずは次の関数定義を見てください.(内容の説明は後ほどします)


def bmi( **kwa ):
w = kwa['weight']
h = kwa['height']
return w/h**2


これは,体重(weight)と身長(height)からBMIを計算する関数 bmi の定義です.

なにやら仮引数にアスタリスクが2つ付けられています.しかも関数定義の内側ではその仮引数が辞書オブジェクトとして扱われています.そしてその辞書を参照する際にキーとして 'weight' と 'height' というものが使われています.
この関数を次のようにして実行してみましょう.


bmi( weight=65, height=1.65 )

実行結果:


23.875114784205696

おわかりいただけるでしょうか.関数を実行する際に「キー = 値」という形の引数を与えています.このような形で関数を呼び出す(実行する)と大変わかりやすいものとなります.これがキーワード引数です.

関数を呼び出す際には,キーワード引数は任意の順序で与えることができます.(次の例)


bmi( height=1.65, weight=65 )

実行結果:


23.875114784205696

引数の順序を先とは逆の順で与えていますが同じ結果が得られています.

このように,キーワード引数を実現するには,関数定義の際の仮引数にアスタリスクを2つ付けます.そして関数内部ではそれを辞書として扱い,キーを指定して参照することができます.

関数の再帰的呼び出し

Pythonでは再帰的な関数定義が可能です.これについて,非負整数 n の階乗 n! の計算を例に挙げて説明します.
非負の階乗の計算は

   n! = n*(n-1)*(n-2)*… *1

で定義できますが,これとは別の書き方

   0! = 1
   n! = n*(n-1)!

という書き方でも定義可能です.こちらの定義は「階乗の定義の中に階乗を使っている」というもので,「再帰的な定義」になっています.(ちょっと不思議な感じがありますが,数学的には正しく定義できています)

この「再帰的な定義」による階乗の関数 fct をPythonで記述してみましょう.(次の例)


def fct(n):
if n == 0:
return 1
else:
return n*fct(n-1)


数学的な定義がそのままプログラムになったような形です.この関数で階乗を計算する例を下に示します.


print( fct(0) )
print( fct(3) )
print( fct(5) )
print( fct(10) )


実行結果:


1
6
120
3628800


実際に計算できていることがわかります.

■ 再帰的プログラミングにおける注意

再帰的な関数定義は数学的にわかりやすい形になることが多いですが,不用意に使用しない方が無難です.なぜなら,再帰的に定義された関数は実行時にコンピュータの記憶資源を多く使用したり,実行時間が大きくなるケースがあるからです.

再帰的に定義可能な関数も,その実装においては,可能な限り通常の繰り返し構文(forやwhileなど)で実現することを検討してください.

■ 関数の再帰的呼び出し回数の上限

先に定義した関数 fct は再帰的に自分自身である fct を呼び出しますが,再帰的な呼び出し回数には上限が設定されています.例えば,1000! を fct(1000) で求めようとすると次のようになります.


fct(1000)

実行結果:


RecursionError Traceback (most recent call last)
〈ipython-input-204-e259a8bd7195> in 1 fct(1000)

1 frames
... last 1 frames repeated, from the frame below ...

in fct(n)
3 return 1
4 else:
----> 5 return n*fct(n-1)

RecursionError: maximum recursion depth exceeded in comparison


これは「再帰呼び出しの回数が多すぎるので実行不可」という意味のエラーです.

では,関数の再帰的呼び出しは何回まで可能でしょうか.それを調べるには sys モジュールを読み込む必要があります.このモジュールを読み込んで,再帰呼び出しの回数の上限を調べる例を次に示します.


import sys
sys.getrecursionlimit()


実行結果:


1000

sys モジュールの getrecursionlimit というメソッドで再帰呼び出しの上限を調べています.これによると,再帰呼び出しの上限が 1000 であることがわかります.1000! の計算はこの回数を少し超えるのでエラーとなったわけですが,sys モジュールの setrecursionlimit メソッドを使うとこの上限値を変更することもできます.

再帰的呼び出し回数をもう少し大きく(1500回に)設定して関数 1000! を計算する例を次に示します.


sys.setrecursionlimit(1500) # 再帰呼び出しの上限を大きくする
fct(1000)


実行結果:


40238726007709377354370243392300398571937486421071463254379991042993851239862902
05920442084869694048004799886101971960586316668729948085589013238296699445909974
24504087073759918823627727188732519779505950995276120874975462497043601418278094
64649629105639388743788648733711918104582578364784997701247663288983595573543251
31853239584630755574091142624174743493475534286465766116677973966688202912073791
43853719588249808126867838374559731746136085379534524221586593201928090878297308
43139284440328123155861103697680135730421616874760967587134831202547858932076716
91324484262361314125087802080002616831510273418279777047846358681701643650241536
91398281264810213092761244896359928705114964975419909342221566832572080821333186
11681155361583654698404670897560290095053761647584772842188967964624494516076535
34081989013854424879849599533191017233555566021394503997362807501378376153071277
61926849034352625200015888535147331611702103968175921510907788019393178114194545
25722386554146106289218796022383897147608850627686296714667469756291123408243920
81601537808898939645182632436716167621791689097799119037540312746222899880051954
44414282012187361745992642956581746628302955570299024324153181617210465832036786
90611726015878352075151628422554026517048330422614397428693306169089796848259012
54583271682264580665267699586526822728070757813918581788896522081643483448259932
66043367660176999612831860788386150279465955131156552036093988180612138558600301
43569452722420634463179746059468257310379008402443243846565724501440282188525247
09351906209290231364932734975655139587205596542287497740114133469627154228458623
77387538230483865688976461927383814900140767310446640259899490222221765904339901
88601856652648506179970235619389701786004081188972991831102117122984590164192106
88843871218556461249607987229085192968193723886426148396573822911231250241866493
53143970137428531926649875337218940694281434118520158014123344828015051399694290
15348307764456909907315243327828826986460278986432113908350621709500259738986355
42771967428222487575867657523442202075736305694988250879689281627538488633969099
59826280956121450994871701244516461260379029309120889086942028510640182154399457
15680594187274899809425474217358240106367740459574178516082923013535808184009699
63725242305608559037006242712434169090041536901059339838357779394109700277534720
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000


1000! が計算できています.

Udemy-logo.gifPython3 の基礎 − 超入門・再入門 −



×

この広告は30日以上新しい記事の更新がないブログに表示されております。