例えば、以下のような簡単な関数を定義しようとしましたが、うまく動作しません。
いや、上手く動作するでしょ?
Python
1>>> def my_function(a, b):
2... c = a + b
3... return c
4...
5>>> result = my_function(1, 2)
6>>> print(result)
73
「うまく動作する」ってのは何だろ。
当然、「返すべき値がある/分かってる」必要があるわけで、「何となく関数を書いた」だけじゃ当然それが上手く設計されたかどうか分からない。
関数の問題じゃないよね。
例えば、上のmy_function
の場合、単に2つ引数(a
とb
)を取り、その和を返すように設計されてる。
したがって、
result = my_function(1, 2)
というテストだと、明らかにresult
に入ってる数値は3だ。
どっちにせよ、テストする前に「その関数が何をする目的の関数なのか」そしてテストして得られるだろう結果にアテが無いとならない。
単純に「うまく動作しません」と言っても意味がないんだ。「うまく動作した結果が何になるか」最初に計算でもしといて把握しとかなきゃなんない。
この関数my_function
は明らかに「上手く動作」してるよ。
defキーワードを使って関数を定義する基本的な構文が知りたいです。
これは簡単でしょ。
Python
1def 関数名(引数1, 引数2, ...):
2 計算過程...
3 return 計算結果
例えば例示だけど、本当だったらこの程度は次のようにして書いた方がいい。
Python
1#!/usr/bin/env python3
2
3def my_function(a, b):
4 return a + b
5
6if __name__ == '__main__':
7 print(my_function(1, 2))
8
もう直接a + b
を返しちゃうね。わざわざc
に代入しない。冗長になるから。
result
なんて変数も用意しない。変数に「代入」するのは、使い回し前提、ってのが原則なんだ。関数内で一回しか登場せんような「計算」はわざわざ代入せんでもエエです。
あと、早いうちに慣れてた方がいい作法は、出力関数(print
)の使用はif __name__ == 'main':
の後に置く。
もっと慣れればユニットテストとか使うかもしんないけど、まぁ、その辺は追々、で。
引数と戻り値の扱い方がよくわかりません。
これも割に良くある説明だけど、基本的には「関数」って言った場合、数学の「関数」と同一視していいです。
引数ってのは単純には数学の関数に於ける独立変数だ。
まぁ、こう言い切っちゃうと、じゃあ「引数に文字列を取った場合は?」とか「引数に構造体を取った場合は?」とかツッコミどころもあるんだけど(笑)、取り敢えずはそう思ってていいです。プログラミング言語に於ける「関数」とは数学で言う関数をベースにした上で、もうちょっと抽象化したもの、と捉える事ができる。
むしろ、プログラミング初心者が意外と概念的に捉えづらいのが「戻り値」の方かね。これはPythonだと「return
する値」を戻り値と呼ぶ、って捉えた方が逆説的だけど分かりやすいかも。
この辺、プログラミング言語の「設計」に纏わる話なんだけど、世の中には「明示的にreturn
」する言語と「暗黙にreturn
する」言語の二種類があるのね。後者は端的に言うと「計算の最後が自動的にreturn
される」言語だ。
例えば、Rubyって言語は基本的には「計算の最後が自動的にreturn
される」。
Ruby
1irb(main):001:1* def foo()
2irb(main):002:1* 1
3irb(main):003:1* 2
4irb(main):004:1* 3
5irb(main):005:0> end
6=> :foo
7irb(main):006:0> foo()
8=> 3
9
Rubyみたいな言語は上の例のように「1、2、3」って並べた場合(何も計算してないように見えるけど、プログラミング上はれっきとした「計算」だ)、1、2、と言う計算結果は捨ててしまって、最後の値3をreturn
する。
一方、同じコードをPythonで書くとこうなる。
Python
1def foo():
2 1
3 2
4 return 3
5
大方のプログラミング言語は、大体そうだと思うんだけど、明示的にreturn
する。上の例だと、1、2を捨てて3をreturn
する。結果関数foo
は3を返す関数になるんだ。
じゃあ、上の構造を利用して2とか1を返せないのか、と問われると、意味はないけど一応できる。
Python
1def bar():
2 1
3 return 2
4 3
5
とかね。こう書けば1と3は捨てられる。より正確に言うと、Python処理系はreturn
を見た時点で、2を持って関数bar
を脱出しちまうんだ。
結果、Pythonでは次のようなプログラムを書くと、文法違反ではないけど、この関数は1しか返さない。
Python
1def baz():
2 return 1
3 return 2
4 3
5
1をreturn
した時点で関数baz
を脱出しちまうんだ。結果、return 2
以降は永遠に実行されない。
return
にはこういう性質があるんで、通常は、「計算過程の最後の値」を戻り値にする為、関数のケツに控えてるわけだ。
引数にデフォルト値を設定することは可能でしょうか?
可能。
例えば次のようにする。
Python
1def foo(default = 'World'):
2 return f'Hello, {default}!'
関数foo
を無引数で呼び出せばデフォルト値が適用される。
Python
1>>> foo()
2'Hello, World!'
3>>> foo('gigantes')
4'Hello, gigantes!'
5
なお、フツーの引数(Pythonでは位置引数と呼ぶ)はデフォルト値を持つ引数(デフォルト引数)の後ろに置くことは出来ない。フツーの引数1、デフォルト引数1、フツーの引数2、・・・みたいには書けないんで気をつけよう。
複数の値を返すにはどうすれば良いでしょうか?
Pythonでは複数の値を返す事は出来ない。複数の値を返すにはそのプログラミング言語は多値関数と言う機能が無いといけない。言い換えると、Pythonは多値関数を持たない。
代わりと言ってはなんだが、Pythonではタプルを用いる。return
する複数の値をコンマで区切って並べる。
Python
1def foo(a, b):
2 return a, b
実行例は例えばこんなカンジだ。
Python
1>>> foo(1, 2)
2(1, 2)
3
タプルで返された値はPythonでは簡単にアンパックできる。
Python
1>>> x, y = foo(1, 2)
2>>> x
31
4>>> y
52
6
関数のスコープについて、具体例を挙げて説明していただけると助かります。
関数内で定義した変数は、関数外からアクセスできないという理解で合っていますか?
そもそも、Pythonはモダンなスコープを全く持っていない。あるのは関数スコープと呼ばれるモノだけ、だ。この辺、Pythonは機能的にはJavaScriptやもはや古典と言えるC言語にさえ負ける。
関数スコープは世界を関数内とその外に分ける。したがって、
関数内で定義した変数は、関数外からアクセスできないという理解で合っていますか?
は合ってるが、同時に、原則的にはPythonでは
関数外で定義した変数は、関数内からアクセスできない
と言う事も忘れちゃならない。これを解決するには、アドホックなglobal
宣言やnonlocal
宣言が必要となる(一方、変数のデータ型がタプル/リストなら関数内からもアクセスできる、と言う変な仕様になっている)。
例えば、ある意味有名な問題だけど、次のような関数を考えよう。
Python
1def foo(n):
2 def bar(i):
3 n += i
4 return n
5 return bar
この関数は実行するとエラーになる。
Python
1>>> s = foo(1)
2>>> s(2)
3Traceback (most recent call last):
4 File "/usr/lib/python3.12/idlelib/run.py", line 580, in runcode
5 exec(code, self.locals)
6 File "<pyshell#18>", line 1, in <module>
7 File "/home/hoge/test.py", line 3, in bar
8 n += i
9 ^
10UnboundLocalError: cannot access local variable 'n' where it is not associated with a value
理由は、ローカルで定義されたローカル関数bar
からはその外側で使われている変数n
が見えないから、だ。こんなエラーはマトモでモダンなスコープを備えた言語じゃ起こり得ないエラーだ。
JavaScript
1> function foo(n) {
2... function bar(i) {
3... n += i;
4... return n;
5... }
6... return bar;
7... }
8undefined
9> var s = foo(1);
10undefined
11> s(2);
123
13> s(3);
146
結果、関数スコープ以外を何も持たないPythonでは、関数bar
内で使ってるn
は、ローカル変数ではない、とnonlocal
宣言しとかないとならない。
Python
1def foo(n):
2 def bar(i):
3 nonlocal n
4 n += i
5 return n
6 return bar
7
ドキュメンテーション文字列(docstring)の書き方と、その重要性について教えてください。
基本的に、ドキュメンテーション文字列ってのは、あくまで書いた関数の「説明」を記述する為のモノなんだよ。
Python
1def first_name(name):
2 '''リストとして表現された名前からファースト・ネームを返す'''
3 return name[0]
そうすると、気の利いたエディタなんかだと、書いた関数をマウスオーバーすると解説を提示してくれたりする。

Pythonにはdoctestって便利な機能があるけど、実はそっちは本懐ではないんだ。
だから「書き方」って意味だと「好きに書けばいい」とは言える。「解説」だからさ。
例えば次のように書く、とか。
Python
1def chocolate(x):
2 '''
3目的: 所持金が与えられたら126円のチョコレートをいくつ買えるかを求める
4chocolate: 整数 -> 整数
5'''
6 return x // 126
7
「目的」では関数の機能を書く。あとは、どういうデータ型を入力してどういうデータ型が返るか書く(もっとも、最近のPythonでは型アノテーションと言う記述法があるが)。
この辺は、言語は違うけど、お茶の水女子大学で公開されているデザインレシピと言う考え方が参考になるだろう。
いくつかの入門サイトを参照しましたが、具体的な例が少なく
まずはPythonチュートリアルを見るようにしよう。
他に、Web上で頼りになる文書には、
がある。
両方とも良く書けてる。