在python3类中使用

2024-10-03 00:16:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图在一个定制的类层次结构中使用子元素属性访问。 我的幻想是,我可以成功地使用描述符来实现这一点。 我想更花哨一些,让类RefHolder(在下面的测试用例中显示)使用插槽来节省空间。在

{I>尝试使用时隙

请注意,我已经尝试过查看现有的解决方案,我能找到的最匹配的解决方案是:

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

我已经在下面的测试用例中尝试过了,但是仍然得到runtimeerror。在

注意,在测试用例中,如果使用注释行而不是它们正下方的行,并且__slots__从{}中删除, 测试用例通过。在

有什么建议吗? 另外,我正在为每个属性访问创建一个对象,这似乎很昂贵,有什么建议可以更有效地实现相同的行为?谢谢!在

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

Tags: nameselfobjgetreturnvaluemydef