2009年05月28日

Pythonクックブック2nd 6.10をPython3.0に移植してみた

メソッドを保持する必要があったので、手元のPython クックブック 第2版を紐解いて「ガベージコレクションを邪魔することなく結合メソッドへのリファレンスを保持」を打ち込んでみたのですが、Python3.0の変更点がいくつかヒットしていてそのままじゃ動きませんでした。元のコードはこちらのコメント欄の一番下のコードです。

使われ方としては以下のサンプルの通り。メソッドをそのまま保持してしまうと、インスタンスメソッドを保持しているオブジェクトまで削除しないと生きたままになってしまうので、weakrefを使うといいよ、という感じのティップスです。

>>> class C:
...   def f(self):
...     print "Hello"
...   def __del__(self):
...     print "C dying"
>>> c = C()
>>> cf = _weekmethod_ref(c.f)
>>> cf()() # この段階ではインスタンスcが生きているので使える
Hello
>>> del c # cを殺してみる
C dying
>>> print cf()
None

コードだけ書くのもいいけど、せっかくなので今回分かったPython2.Xと3.Xの違いもまとめておきます。

まずは完成系。これでPython3.0でも動作します。

import weakref, types

class _weekmethod_ref:
    def __init__(self, fn):
        try:
            o, f = fn.__self__, fn.__func__
        except AttributeError:
            self._obj = None
            self._func = fn
        else:
            self._obj = weakref.ref(o)
            self._func = f

    def __call__(self):
        if self._obj is None:
            return self._func
        elif self._obj() is None:
            return None
        return types.MethodType(self._func, self._obj())

このコードの中での2.Xと3.Xの違いは以下の通りです。

Python2系

  • メソッドのオブジェクトは以下の属性を持つ
    • im_self(メソッドが属すインスタンス)
    • im_func(関数オブジェクト)
    • im_class(メソッドが属すインスタンスのクラス)
  • 各種組み込み型のオブジェクトを作成するnewモジュールがある

Python3系

  • メソッドのオブジェクトは以下の属性を持つ
    • __self__(im_selfと同じ)
    • __func__(im_funcと同じ)
  • newモジュールはない。代わりにtypesモジュールを使う

2.Xと3.Xではメソッド呼び出しはそれぞれ以下のように解釈されます。

# Python2.X
m.im_func(m.im_self, arg_1, arg_2, arg_3) 
# Python3.X
m.__func__(m.__self__, arg_1, arg_2, arg_3) 

また、インスタンスメソッドを自前で作るやり方もそれぞれ以下のように変わります。Python 2.Xではインスタンスになる前のクラスに属している段階のメソッドは非束縛メソッド(UnboundMethodType)という型ですが、Python3.Xでは通常の関数(FunctionType)です。非束縛メソッドと違い、所属するクラス(3番目のパラメータ)を持たなくなっていますが、そのあたりの経緯はThe History of Pythonにちょっと書かれています。インスタンス化されるときに型が変わってメソッド(MethodType)になります。非束縛メソッドがないので、完成系のコードからは非束縛メソッドのチェックも外してあります。

# Python2.X
method = new.instancemethod(m.im_func, m.im_self, m.im_class) 
# Python3.X
method = types.MethodType(m.__func__, m.__self__) 

ここまで自作することは普段はないと思いますけどね。そうそう、非束縛メソッドがなくなってしまったので、クラスの状態で、メソッドかstaticメソッドかの区別がつかなくなってしまいました。@staticmethodデコレータを付けるとstaticになりますので、何か違いは記録されているはずなんですけどね。ソースコードをみて、staticmethodというモノが関数ではなくてクラスということは突き止めたけど、それ以上はまだ分かってません。

部分的にどんどん古くなってしまうのは仕方ないですが、この本は中級以上のPythonプログラマにはかなりオススメです。他言語の人でもアイディアは色々もらえるかも。

posted by @shibukawa at 22:08 | Comment(204) | TrackBack(0) | Python はてなブックマーク - Pythonクックブック2nd 6.10をPython3.0に移植してみた
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/29437040
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック
検索ボックス

Twitter

www.flickr.com
This is a Flickr badge showing public photos and videos from shibukawa.yoshiki. Make your own badge here.
<< 2019年02月 >>
          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    
最近の記事
カテゴリ
過去ログ
Powered by さくらのブログ