いろいろ備忘録日記

主に .NET とか Java とか Python絡みのメモを公開しています。

Pythonメモ-41 (__weakref__ 属性) (weakref, 弱参照, ユーザ定義クラス, __slots__)

概要

devlights.hatenablog.com

前回の補足メモ。

弱参照を作った際、python データモデルでは、オブジェクトの __weakref__属性に

設定されるとのこと。試してみると

set01 = {1, 2}
wref = weakref.ref(set01)
print(hasattr(set01, '__weakref__'))

出力結果は

False

存在しないじゃんって思ったら、これはユーザ定義クラスのみに存在する属性なのですね。

class A:
  pass

a = A()
wref = weakref.ref(a)
print(hasattr(a, '__weakref__'))

出力結果は

True

この属性は、ユーザ定義クラスにて弱参照をサポートする際に必要になります。

なので、オブジェクトのメモリサイズ最適化のために __slots__をつかって

定義する際に、弱参照をサポートさせる場合は __weakref__を含めておく必要があります。

class B:
  __slots__ = ('val')

  def __init__(self, val):
    self.val = val

b = B()
wref = weakref.ref(b)

とすると、以下のようになります。

TypeError: cannot create weak reference to 'B' object

__slots__に含めてみます。

class C:
  __slots__ = ('val', '__weakref__')

  def __init__(self, val):
    self.val = val

c = C(100)
wref = weakref.ref(c)

今度はエラーなく処理できました。

サンプル

# coding: utf-8
"""
weakref モジュールについてのサンプルです。

弱参照がオブジェクトの __weakref__ に設定されることを確認するサンプルです。
"""
import weakref

from trypython.common.commoncls import SampleBase
from trypython.common.commonfunc import pr


# noinspection PyUnusedLocal,SpellCheckingInspection,PyUnresolvedReferences
class Sample(SampleBase):
    def exec(self):
        # ------------------------------------------------
        # 弱参照は、オブジェクトの
        #   __weakref__
        # に設定される。
        #
        # ただし、この属性が存在するのは
        #   ユーザ定義クラス 
        # の場合のみ。
        # ------------------------------------------------
        set01 = {1, 2}
        wref = weakref.ref(set01)
        pr('__weakref__ exists?', hasattr(set01, '__weakref__'))

        a = A()
        wref = weakref.ref(a)
        pr('__weakref__ exists?', hasattr(a, '__weakref__'))
        pr('a.__weakref__ is wref', a.__weakref__ is wref)

        # ------------------------------------------------
        # ユーザ定義クラスで弱参照をサポートするためには
        # __weakref__ 属性が必要となる。__slots__ 属性を
        # つかって、オブジェクトのメモリサイズを最適化している
        # 場合、この属性を含めていないと弱参照が作れない。
        # ------------------------------------------------
        b = NotContainsWeakrefAttr(100)
        try:
            bref = weakref.ref(b)
        except TypeError as e:
            pr('NotContainsWeakrefAttr', e)

        c = ContainsWeakrefAttr(100)
        cref = weakref.ref(c)
        print(cref)


class A:
    pass


class NotContainsWeakrefAttr:
    __slots__ = ('val',)

    def __init__(self, val):
        self.val = val


class ContainsWeakrefAttr:
    __slots__ = ('val', '__weakref__',)

    def __init__(self, val):
        self.val = val


def go():
    obj = Sample()
    obj.exec()


if __name__ == '__main__':
    go()

出力結果は以下の通り。

__weakref__ exists?=False
__weakref__ exists?=True
a.__weakref__ is wref=True
NotContainsWeakrefAttr=TypeError("cannot create weak reference to 'NotContainsWeakrefAttr' object",)
<weakref at 0x00000000056C11D8; to 'ContainsWeakrefAttr' at 0x00000000056C04A8>

参考情報

3. データモデル — Python 3.6.3 ドキュメント

Fluent Python ―Pythonicな思考とコーディング手法

Fluent Python ―Pythonicな思考とコーディング手法

  • 作者: Luciano Ramalho,豊沢聡,桑井博之,梶原玲子
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2017/10/07
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。