変数は定義される位置によって, スコープと呼ばれる有効範囲が異なります. 関数は独自のスコープを作り, 関数内部で定義される変数を関数の外側で使うことはできないようになっています.
次の振る舞いを確認してください.
In [1]: y = 'hello'
In [2]: z = 100
In [3]: def f(x):
...: y = 2
...: z = -1
...: return x*2 + z
...:
In [4]: f(1)
Out[4]: 1
In [5]: y
Out[5]: 'hello'
In [6]: z
Out[6]: 100
関数の内部で定義されていた変数は, 関数の内部でのみ有効です. 一方, 関数の外側で定義された変数を使うことは可能です. ただし, 意図しない結果を招く恐れがあるので, このようなコードを書く必然性がなければ避ける方が懸命でしょう.
In [7]: g = 10
In [8]: def f(x):
...: return g * x
...:
In [9]: f(10)
Out[9]: 100
In [10]: g = 20 # 一見 f とは関係がないような変更
In [11]: f(10) # しかし, f の挙動を変えてしまっている
Out[11]: 200
次のように書くほうが安全です.
In [12]: def f(x, g):
....: return g * x
....:
In [13]: f(10, g=10)
Out[13]: 100
In [14]: f(10, g=20)
Out[14]: 200
あるいは, 次のように書くのもよいかもしれません.
In [15]: def fg(g):
....: def _f(x):
....: return g * x
....: return _f
....:
In [16]: f = fg(10)
In [17]: f(10)
Out[17]: 100
In [18]: f = fg(20) # 明示的な変更
In [19]: f(10)
Out[19]: 200
すでに上で例を出しましたが, 関数呼び出しの際に func_name(仮引数名=実引数)
の形で
引数を渡すことができます. 次の関数を例にとって説明しましょう.
In [20]: def hello(name, title):
....: print('Hello,', title, name, '!')
....:
以下の呼び出し方法が認められています.
In [21]: hello('Brown', 'Ms.') # 位置指定引数
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-21-1c05f23cc965> in <module>()
----> 1 hello('Brown', 'Ms.') # 位置指定引数
<ipython-input-20-822ec1be3fb5> in hello(name, title)
1 def hello(name, title):
----> 2 print('Hello,', title, name, '!')
3
TypeError: 'int' object is not callable
In [22]: hello(name='Brown', title='Mr.') # キーワード引数
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-87c81f4b39d7> in <module>()
----> 1 hello(name='Brown', title='Mr.') # キーワード引数
<ipython-input-20-822ec1be3fb5> in hello(name, title)
1 def hello(name, title):
----> 2 print('Hello,', title, name, '!')
3
TypeError: 'int' object is not callable
In [23]: hello(title='Mr.', name='Brown') # キーワード引数は順序交換可
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-23-42d5f7430632> in <module>()
----> 1 hello(title='Mr.', name='Brown') # キーワード引数は順序交換可
<ipython-input-20-822ec1be3fb5> in hello(name, title)
1 def hello(name, title):
----> 2 print('Hello,', title, name, '!')
3
TypeError: 'int' object is not callable
In [24]: hello('Brown', title='Mr.') # 2個目だけキーワードというのも可
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-24-473e4ab22e3a> in <module>()
----> 1 hello('Brown', title='Mr.') # 2個目だけキーワードというのも可
<ipython-input-20-822ec1be3fb5> in hello(name, title)
1 def hello(name, title):
----> 2 print('Hello,', title, name, '!')
3
TypeError: 'int' object is not callable
しかし, 以下のような呼び出しは認められていません.
In [25]: hello('Mr.', name='Brown') # 1
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-25-f3293e11e39c> in <module>()
----> 1 hello('Mr.', name='Brown') # 1
TypeError: hello() got multiple values for argument 'name'
In [26]: hello(title='Mr.', 'Brown') #2
File "<ipython-input-26-b52af31840cc>", line 1
hello(title='Mr.', 'Brown') #2
^
SyntaxError: non-keyword arg after keyword arg
'President'
は name
変数に代入されているので,
name
キーワード引数があると2度代入しようとして TypeError
になる.SyntaxError
)これらのエラーはエラーメッセージをきちんと読めば対応できるでしょう.
Python 3.x では, 次のように関数を定義することができます.
In [27]: def my_print(s, *, reverse):
....: if reverse:
....: print(s[::-1])
....: else:
....: print(s)
....:
*
よりあとに書かれた仮引数は, キーワード引数としてのみ渡すことができます
(keyword-only argument).
In [28]: my_print('abc', reverse=True)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-28-7f51e34811fd> in <module>()
----> 1 my_print('abc', reverse=True)
<ipython-input-27-d94dc7c4b3cc> in my_print(s, reverse)
1 def my_print(s, *, reverse):
2 if reverse:
----> 3 print(s[::-1])
4 else:
5 print(s)
TypeError: 'int' object is not callable
In [29]: my_print('abc', reverse=False)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-29-0566970688b9> in <module>()
----> 1 my_print('abc', reverse=False)
<ipython-input-27-d94dc7c4b3cc> in my_print(s, reverse)
3 print(s[::-1])
4 else:
----> 5 print(s)
6
TypeError: 'int' object is not callable
これは, 次のような呼び出しを禁止するために使われます. (True
が意味するものが何かが
わかりにくいとコードの可読性が下がってしまうのです)
In [30]: my_print('error', True)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-30-dc202b040992> in <module>()
----> 1 my_print('error', True)
TypeError: my_print() takes 1 positional argument but 2 were given
関数にはデフォルト値を指定することができます.
In [31]: def salute(name, title, msg='Hello'):
....: print(msg + ',', title, name + '!')
....:
In [32]: salute('Brown', 'Mr.')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-32-62c89680e02a> in <module>()
----> 1 salute('Brown', 'Mr.')
<ipython-input-31-8ab58816c14f> in salute(name, title, msg)
1 def salute(name, title, msg='Hello'):
----> 2 print(msg + ',', title, name + '!')
3
TypeError: 'int' object is not callable
In [33]: salute('Brown', 'Mr.', 'Good morning')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-33-e4f8e8313238> in <module>()
----> 1 salute('Brown', 'Mr.', 'Good morning')
<ipython-input-31-8ab58816c14f> in salute(name, title, msg)
1 def salute(name, title, msg='Hello'):
----> 2 print(msg + ',', title, name + '!')
3
TypeError: 'int' object is not callable
デフォルト値として None
がよく使われます. 特定の引数が設定されているときと
そうでないときで関数の振る舞いを変えたい場合に使います.