1.2.4. 関数を定義する

1.2.4.1. 関数定義

In [56]: def test():
....: print('in test function')
....:
....:
In [57]: test()
in test function

警告

関数ブロックは制御フローブロックと同様にインデントされる必要があります.

1.2.4.2. return 文

関数は オプションとして 値を返すことができます.

In [6]: def disk_area(radius):
...: return 3.14 * radius * radius
...:
In [8]: disk_area(1.5)
Out[8]: 7.0649999999999995

注釈

By default, functions return None.

注釈

関数定義構文の注解:

  • def キーワード

  • 続けて関数の 名前, そして

  • 丸括弧の間に関数の引数を与え、続けてコロン

  • 関数の本体;

  • そしてオプションとして値を返すために return object する

1.2.4.3. 引数

必須の引数(固定引数)

In [81]: def double_it(x):
....: return x * 2
....:
In [82]: double_it(3)
Out[82]: 6
In [83]: double_it()
---------------------------------------------------------------------------
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: double_it() takes exactly 1 argument (0 given)

オプションの引数(キーワード引数または名前付き引数)

In [84]: def double_it(x=2):
....: return x * 2
....:
In [85]: double_it()
Out[85]: 4
In [86]: double_it(3)
Out[86]: 6

キーワード引数は デフォルトの値 を持つことができます.

警告

デフォルトの値は関数が呼び出されたときではなく, 定義されたときに評価されます。これは変更可能な型(例 辞書やリスト)を利用しているときに問題になります、これらを関数本体の中で変更すると変更は関数の呼び出しをまたいで継続されます。

変更不可能な型をキーワード引数で使ってみます:

In [124]: bigx = 10
In [125]: def double_it(x=bigx):
.....: return x * 2
.....:
In [126]: bigx = 1e9 # Now really big
In [128]: double_it()
Out[128]: 20

変更可能な型をキーワード引数で使ってみます(そして関数の中で変更します)

In [2]: def add_to_dict(args={'a': 1, 'b': 2}):
...: for i in args.keys():
...: args[i] += 1
...: print args
...:
In [3]: add_to_dict
Out[3]: <function __main__.add_to_dict>
In [4]: add_to_dict()
{'a': 2, 'b': 3}
In [5]: add_to_dict()
{'a': 3, 'b': 4}
In [6]: add_to_dict()
{'a': 4, 'b': 5}

ちなみに

python のスライスを実装した, より複雑な例:

In [98]: def slicer(seq, start=None, stop=None, step=None):
....: """Implement basic python slicing."""
....: return seq[start:stop:step]
....:
In [101]: rhyme = 'one fish, two fish, red fish, blue fish'.split()
In [102]: rhyme
Out[102]: ['one', 'fish,', 'two', 'fish,', 'red', 'fish,', 'blue', 'fish']
In [103]: slicer(rhyme)
Out[103]: ['one', 'fish,', 'two', 'fish,', 'red', 'fish,', 'blue', 'fish']
In [104]: slicer(rhyme, step=2)
Out[104]: ['one', 'two', 'red', 'blue']
In [105]: slicer(rhyme, 1, step=2)
Out[105]: ['fish,', 'fish,', 'fish,', 'fish']
In [106]: slicer(rhyme, start=1, stop=4, step=2)
Out[106]: ['fish,', 'fish,']

キーワード引数はどんな順序で書いても問題ありません:

In [107]: slicer(rhyme, step=2, start=1, stop=4)
Out[107]: ['fish,', 'fish,']

しかし, 関数定義と同じ順序で書くこと方がいい習慣とされます.

キーワード引数 は多くの引数を持つ関数を定義するのにとても便利な機能です, とりわけ, 多くの値がデフォルトの値を持つような関数で特に便利です.

1.2.4.4. 値渡し

ちなみに

関数内部の変数に変更を加えることはできるでしょうか? 多くの言語 (C, Java, ...) では「値渡し」と「参照渡し」を区別します . Python ではこのような区別はいくぶん不自然で, 変数が変更されるのかについては少々わかりにくいところがあります. しかし, 幸運なことに明解な規則があります.

関数の引数はオブジェクトの参照が値として渡されます. 関数に変数を渡すとき, Python は変数を参照しているオブジェクト()を渡します. 変数自身は渡しません.

関数に渡された が変化不可能なら、関数は呼び出し元の変数を変更しません. もし が変更可能なら, 関数は呼び出し元の変数をインプレースに変更する可能性があります:

>>> def try_to_modify(x, y, z):
... x = 23
... y.append(42)
... z = [99] # new reference
... print(x)
... print(y)
... print(z)
...
>>> a = 77 # immutable variable
>>> b = [99] # mutable variable
>>> c = [28]
>>> try_to_modify(a, b, c)
23
[99, 42]
[99]
>>> print(a)
77
>>> print(b)
[99, 42]
>>> print(c)
[28]

関数はローカルな変数テーブルを持っています, それは ローカルな名前空間 と呼ばれます.

変数 xtry_to_modify 関数の中でのみ存在します.

1.2.4.5. グローバル変数

関数の外で宣言された変数は関数内部で呼び出すことができます:

In [114]: x = 5
In [115]: def addx(y):
.....: return x + y
.....:
In [116]: addx(10)
Out[116]: 15

しかし, これらの “グローバル” 変数は関数の中で変更することはできません, ただし関数内で global と宣言すれば可能になります.

これは動きません:

In [117]: def setx(y):
.....: x = y
.....: print('x is %d' % x)
.....:
.....:
In [118]: setx(10)
x is 10
In [120]: x
Out[120]: 5

これは動きます:

In [121]: def setx(y):
.....: global x
.....: x = y
.....: print('x is %d' % x)
.....:
.....:
In [122]: setx(10)
x is 10
In [123]: x
Out[123]: 10

1.2.4.6. 可変数引数

引数の特別な形式:
  • *args: 任意の固定引数が入ったタプル

  • **kwargs: 任意のキーワード引数が入った辞書

In [35]: def variable_args(*args, **kwargs):
....: print 'args is', args
....: print 'kwargs is', kwargs
....:
In [36]: variable_args('one', 'two', x=1, y=2, z=3)
args is ('one', 'two')
kwargs is {'y': 2, 'x': 1, 'z': 3}

1.2.4.7. docstring

関数が何をするのかとその引数についてのドキュメントを書くのに一般的なとりきめとして:

In [67]: def funcname(params):
....: """Concise one-line sentence describing the function.
....:
....: Extended summary which can contain multiple paragraphs.
....: """
....: # function body
....: pass
....:
In [68]: funcname?
Type: function
Base Class: type 'function'>
String Form: <function funcname at 0xeaa0f0>
Namespace: Interactive
File: <ipython console>
Definition: funcname(params)
Docstring:
Concise one-line sentence describing the function.
Extended summary which can contain multiple paragraphs.

注釈

docstring に関するガイドライン

標準化の目的のために, Docstring Conventions の Web ページに python の docstring に関する意味論と取り決めが文書化されています.

また Numpy や Scipy モジュールも科学技術計算用の関数の文書化のために簡潔化された標準を定めています, それらは, 引数 の節や Example の節等を含んでいて, 自分で書いた関数について参考にしたいと思うことでしょう. http://projects.scipy.org/numpy/wiki/CodingStyleGuidelines#docstring-standardhttp://projects.scipy.org/numpy/browser/trunk/doc/example.py#L37 を参照してください.

1.2.4.8. 関数はオブジェクト

関数はファーストクラスオブジェクトです、つまり以下のことができます:
  • 値に代入

  • リスト(任意のコレクションでも可)の項目

  • 別の関数の引数として渡す

In [38]: va = variable_args
In [39]: va('three', x=1, y=2)
args is ('three',)
kwargs is {'y': 2, 'x': 1}

1.2.4.9. メソッド

メソッドはオブジェクトと結びついた関数です. これまで リスト, 辞書, 文字列 等の例の中でみてきました.

1.2.4.10. 練習問題

練習問題: Fibonacci 数列

Fibonacci 数列の第 n 項までを表示する関数を書きましょう, Fibonacci 数列の定義は:

  • u_0 = 1; u_1 = 1
  • u_(n+2) = u_(n+1) + u_n

練習問題: クイックソート

クイックソートアルゴリズムを実装しましょう, Wikipedia での定義:

function quicksort(array)
var list less, greater
if length(array) < 2
return array
select and remove a pivot value pivot from array
for each x in array
if x < pivot + 1 then append x to less
else append x to greater
return concatenate(quicksort(less), pivot, quicksort(greater))