Dive into Python 3のchapter 6をざっと読んでみた。
Pythonの関数はオブジェクトである。これはRubyの関数(メソッド)と非常に大きく異なる点だ。Pythonだと
>>> def foo():のように変数に直接関数を代入したり、代入した変数経由で元の関数を呼び出したりできる。…と言うか
.. print('foo')
..
>>> f = foo
>>> f()
foo
>>> foo = 1こんなことができてしまうということは、fooは定数ですらないようだ。Pythonのdef文は、JavaScriptのfunctionと同じように関数オブジェクトを作って、それを何の変哲も無い普通の変数に代入しているだけみたい。
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>> foo = f
>>> foo()
foo
とにもかくにも、関数がオブジェクトであるということは、100やら'abc'やらと同じように普通に受け渡しが出来る。ここは正直Rubyの弱いところで、基本的に最大1つのブロックをメソッドに渡すことしかできない。一応:funcのようなシンボルでメソッド名を渡したり、lambda等でProcオブジェクトを作って渡したり、呼び出し先でevalしてもらうコードを文字列で渡したりすることはできるのだけれど、自然に関数を扱えるとは言い難い。まあ、Rubyではメソッドが特別扱いされているが故に
print 'ruby'のように()を付けなくてもメソッド呼び出し出来るのは、ちゃちゃっと使い捨てコードを書くときに楽は楽なんだけど。
もう1点。RubyのProcにはないけどPythonの関数オブジェクトにはある機能に、中断/再開がある。
>>> def gen():このように、内部でyield文を使った関数はgeneratorクラスのオブジェクトを返す。そして
... v = 0
... while v <= 50:
... yield v
... v += 10
...
>>> g = gen()
>>> type(g)
<class 'generator'>
>>> next(g)このようにnext文でgeneratorを呼び出す度に、関数オブジェクトがyieldした値が呼び出し元に返され、また関数オブジェクトの方はyieldしたところで中断する。ノンプリエンプティブなスレッドと言えなくもない。このgeneratorの嬉しいのは、リスト等と同じように
0
>>> next(g)
10
>>> next(g)
20
>>> next(g)
30
>>> next(g)
40
>>> next(g)
50
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> for i in gen():こんな感じでイテレータとして使えるところ。イテレータの話は次の章で深追いするのかな?
... print(i)
...
0
10
20
30
40
50
0 件のコメント:
コメントを投稿