1

Python 3.2 で導入されたモジュール 内の関数recursive_reprには、次のソース コードがあります。reprlib

def recursive_repr(fillvalue='...'):
    'Decorator to make a repr function return fillvalue for a recursive call'

    def decorating_function(user_function):
        repr_running = set()

        def wrapper(self):
            key = id(self), get_ident()
            if key in repr_running:
                return fillvalue
            repr_running.add(key)
            try:
                result = user_function(self)
            finally:
                repr_running.discard(key)
            return result

        # Can't use functools.wraps() here because of bootstrap issues
        wrapper.__module__ = getattr(user_function, '__module__')
        wrapper.__doc__ = getattr(user_function, '__doc__')
        wrapper.__name__ = getattr(user_function, '__name__')
        wrapper.__annotations__ = getattr(user_function, '__annotations__', {})
        return wrapper

    return decorating_function

key特定の機能の識別__repr__は に設定されます(id(self), get_ident())

なぜselfそれ自体がキーとして使用されなかったのですか? そして、なぜget_ident必要だったのですか?

4

1 に答える 1

1

次のコードを検討してください。

a = []
b = []
a.append(b)
b.append(a)
a == b

これにより、スタック オーバーフローが発生します。しかし、アルゴリズムはこのケースを安全に処理する必要があります。セットに入れると、self使用して比較され==、アルゴリズムは失敗します。id(self)そのため、オブジェクトの等価性をチェックしようとしない代わりに使用します。まったく同じオブジェクトであるかどうかだけを気にします。

についてget_indentは、2 つのスレッドが同時にコードを使用しようとした場合に、このアルゴリズムで何が起こるかを考えてみてください。セットはすべてのrepr_runningスレッド間で共有されます。しかし、複数のスレッドがそのセットから要素を追加および削除し始めた場合、何が起こるかわかりません。get_ident()はそれを実行しているスレッドに固有であるため、それをキーで使用することにより、すべてのスレッドが異なるキーを使用しても問題ないことがわかります。

于 2012-07-31T20:04:04.947 に答える