Python 如何将查找深度作为类属性检查到嵌套字典中?
我根据在那里找到的Python 如何将查找深度作为类属性检查到嵌套字典中?,python,dictionary,nested,attributes,Python,Dictionary,Nested,Attributes,我根据在那里找到的AttrDict创建了一个嵌套字典: 我将其修改为在“leaves”中包含str命令,该命令在请求/写入值时执行: commands = {'root': {'com': {'read': 'READ_CMD', 'write': 'WRITE_CMD'} } } class AttrTest() def __init__: self.__dict__['attr'] = AttrDict(commands) test = AttrTest() d
AttrDict
创建了一个嵌套字典:
我将其修改为在“leaves”中包含str
命令,该命令在请求/写入值时执行:
commands = {'root': {'com': {'read': 'READ_CMD', 'write': 'WRITE_CMD'} } }
class AttrTest()
def __init__:
self.__dict__['attr'] = AttrDict(commands)
test = AttrTest()
data = test.attr.root.com.read # data = value read with the command
test.attr.root.com.write = data # data = value written on the com port
虽然它工作得很好,但我想:
- 避免人们访问
/attr
/root
,因为这会返回一个子级别的命令com
- 人们直接访问attr.root.com(通过
/获取属性
)设置属性
- 如上所述,当访问嵌套dict的“trunk”时,我得到了“leaves”的部分dict
- 访问
时,它返回attr.root.com
{'read':'read\u CMD','write':'write\u CMD'}
- 如果检测到
,我将进行正向查找并返回值,但是读取
失败attr.root.com.read
- 阻止访问
/attr
root
- 直接访问
读取/写入值(使用正向查找)attr.root.com
- 仅当请求
或attr.root.com.read
时才返回所需的部分dictattr.root.com.write
感谢您的考虑。对于给定的属性查找,您无法确定将有多少其他属性跟随;这就是Python的工作原理。为了解析
x.y.z
,首先需要检索对象x.y
,然后才能执行后续的属性查找(x.y).z
但是,您可以返回一个代表(部分)路径的代理对象,而不是存储在dict中的实际底层对象。因此,例如,如果您执行了test.attr.com
,那么这将返回一个代表路径attr.com
的代理对象,以便在test
对象上查找。只有在路径中遇到read
或write
叶时,才能解析路径并读取/写入数据
以下是一个示例实现,它使用基于\uuuu getattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
从functools导入reduce
类别属性(dict):
def _ugetattr _;(self,name):
返回代理(self,(name,))
定义解析(自身、路径):
返回归约(λd,k:d[k],路径,自)
类代理:
定义初始化(自、对象、路径):
对象.uuuu setattr_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
对象。uuuu setattr_uuuuuuuuuu(自,u路径,u路径)
定义(自我):
返回f“路径”
def _ugetattr _;(self,name):
如果name=='read':
返回self.\u obj.\u解析(self.\u路径)[名称]
其他:
返回类型(self)(self.\u对象,(*self.\u路径,名称))
定义设置属性(自身、名称、值):
如果名称!='在(_dict:=self.\u obj.\u resolve(self.\u path))中写入“或名称”:
raise AttributeError(f'无法为{self}'设置属性{name!r})
_dict[name]=值
命令={'root':{'com':{'read':'read_CMD','write':'write_CMD'}}
test=AttrDict({'attr':commands})
打印(f'{test.attr=!s}')#路径
打印(f'{test.attr.root=!s}')#路径
打印(f'{test.attr.root.com=!s}')#路径
打印(f'{test.attr.root.com.read=!s}')#read_CMD
test.attr.root.com.write='test'
test.attr.root.write='非法'#引发AttributeError
from functools import reduce
class AttrDict(dict):
def __getattr__(self, name):
return Proxy(self, (name,))
def _resolve(self, path):
return reduce(lambda d, k: d[k], path, self)
class Proxy:
def __init__(self, obj, path):
object.__setattr__(self, '_obj', obj)
object.__setattr__(self, '_path', path)
def __str__(self):
return f"Path<{'.'.join(self._path)}>"
def __getattr__(self, name):
if name == 'read':
return self._obj._resolve(self._path)[name]
else:
return type(self)(self._obj, (*self._path, name))
def __setattr__(self, name, value):
if name != 'write' or name not in (_dict := self._obj._resolve(self._path)):
raise AttributeError(f'Cannot set attribute {name!r} for {self}')
_dict[name] = value
commands = {'root': {'com': {'read': 'READ_CMD', 'write': 'WRITE_CMD'} } }
test = AttrDict({'attr': commands})
print(f'{test.attr = !s}') # Path<attr>
print(f'{test.attr.root = !s}') # Path<attr.root>
print(f'{test.attr.root.com = !s}') # Path<attr.root.com>
print(f'{test.attr.root.com.read = !s}') # READ_CMD
test.attr.root.com.write = 'test'
test.attr.root.write = 'illegal' # raises AttributeError