0

私は、カスタム クラス階層でのサブ要素属性へのアクセスにすべて気を配ろうとしています。私の空想は、これを行うために記述子をうまく使用できるという点で機能します。私はさらに凝って、スペースを節約するためにスロットRefHolderを使用するクラス (以下のテストケースに表示)を作成したいと考えています。

ただし、スロットを使用しようとすると、RuntimeError: maximum recursion depth exceeded

私はすでにこれに対する既存の解​​決策を調べてみたことに注意してください.最もよく一致するのはこれです:

https://stackoverflow.com/a/19566973/1671693

以下のテストケースでこれを試しましたが、まだランタイム エラーが発生します。

テストケースで、コメント行がその直下の行の代わりに使用され、__slots__から削除されたRefHolder場合、テストケースはパスすることに注意してください。

助言がありますか?さらに、コストがかかると思われるすべての属性アクセスに対してオブジェクトを作成していますが、同じ動作を実現するより効率的な方法について何か提案はありますか? ありがとう!

import unittest

class RefHolder():
    __slots__ = ['__obj', 'get_value']
    def __init__(self, obj, get_value=False):
        self.__dict__['__obj'] = obj
        self.__dict__['get_value']=get_value

    def get_sub(self, name):
        #attr = self.__dict__['__obj'].find_by_name(name)
        attr = self.__dict__['__obj'].__get__(self, RefHolder).find_by_name(name)
        if attr is None:
            raise AttributeError("Can't find field {}".format(name))
        return attr

    def __getattr__(self, name):
        attr = self.get_sub(name)

        #if self.__dict__['get_value']:
        if self.__dict__['get_value'].__get__(self, RefHolder):
            return attr.Value
        else:
            return attr

    def __setattr__(self, name, value):
        attr = self.get_sub(name)

        #if self.__dict__['get_value']:
        if self.__dict__['get_value'].__get__(self, RefHolder):
            attr.Value = value
        else:
            raise AttributeError("{} is read only in this context".format(name))

class ContainerAccess():
    __slots__ = ['get_value']
    def __init__(self, get_value=False):
        self.get_value = get_value
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return RefHolder(obj, self.get_value)
    def __set__(self, obj, value):
        raise AttributeError("Read Only attribute".format(value))

class PropVal():
    def __init__(self, val):
        self.Value = val
    @property
    def Value(self):
        return self._value
    @Value.setter
    def Value(self, value):
        self._value = value


class T():
    get = ContainerAccess()
    getv = ContainerAccess(get_value=True)
    def __init__(self):
        self.store = {}
        self._value = 0
    def find_by_name(self, name):
        return self.store.get(name)

class T2(T):
    pass

class TestDesc(unittest.TestCase):
    def test_it(self):
        t = T()
        t2 = T2()
        t.store['my_val'] = PropVal(5)
        t.store['my_val2'] = PropVal(6)
        t2.store['my_val'] = PropVal(1)
        self.assertEqual(t.get.my_val.Value, 5)
        self.assertEqual(t.get.my_val2.Value, 6)
        self.assertEqual(t2.get.my_val.Value, 1)
        t.get.my_val.Value = 6
        self.assertEqual(t.get.my_val.Value, 6)
        with self.assertRaises(AttributeError):
            t.get.blah.Value = 6
            #self.assertEqual(t.get.my_other_val.Value, None)

        self.assertEqual(t.getv.my_val, 6)
        t.getv.my_val = 7
        self.assertEqual(t.getv.my_val, 7)
        with self.assertRaises(AttributeError):
            t.get.my_val = 7
4

0 に答える 0