我有一个继承自dict类的类devices
。 devices是一本字典词典。我想通过使用方法调用语法,以及使用普通语法来访问其键和值。即。
class Devices(dict):
def __init__(self):
self['device'] = {'name':'device_name'}
def __getattr__(self, name):
value = self[name]
return value
...
mydevices = Devices()
mydevice = mydevices.device #works and mydevices['device'] also works
#But what code do I need for the following?
name = mydevices.device.name
mydevices.device.name = 'another_name'
我知道如果我覆盖__getattr__
和__setattr__
方法,我可以实现这一点,但正如您从我的代码中看到的,我不知道如何访问嵌套字典。
有谁知道如何实现这个目标?
谢谢,labjunky
答案 0 :(得分:2)
所以无论如何你的答案都非常完整。您可以使用以下方法定义所需的结构类型:
class Devices(dict):
def __init__(self,inpt={}):
super(Devices,self).__init__(inpt)
def __getattr__(self, name):
return self.__getitem__(name)
def __setattr__(self,name,value):
self.__setitem__(name,value)
然后一个用例是:
In [6]: x = Devices()
In [7]: x.devices = Devices({"name":"thom"})
In [8]: x.devices.name
Out[8]: 'thom'
基本上只需嵌套属性查找词典。
答案 1 :(得分:1)
通常,要访问字典值,请使用dictionary[key]
而不是dictionary.key
。在第一种情况下,属性方式有效,因为您覆盖了__getattr__
而不是__getitem__
。这就是为什么它只适用于你的课程,而不适用于内部字典。
现在,要访问__getitem__
中的字典(__getattr__
是属性,例如dict.keys
,其中单词keys
是属性),您需要有点小心。您需要调用字典类的__getitem__
(否则您将有无限递归)。有两种方法可以实现它。如果您选择改变对象遗传,第一个将是持久的:
def __getitem__(self, name):
value = super(Devices,self).__getitem__(name)
return value
另一种方式是:
def __getitem__(self, name):
value = dict.__getitem__(self, name)
return value
如果您仍想使用属性来访问这些值,那么每当您使用该字典时,您都必须将该字典替换为您的字典(因此self['device'] = {'name':'device_name'}
将成为self['device'] = MyDictClass({'name':'device_name'})
。
顺便说一句:请注意__init__
中有错误。 self = {'device':{'name':'device_name'}}
中的__init__
行实际上并没有做任何事情。 (它将字典放在局部变量self
中,但是一旦退出函数,此变量就会消失。)
您应该使用更改对象本身的操作。即:
def __init__(self):
self['device'] = {'name':'device_name'}
答案 2 :(得分:1)
您可以使用这个棘手的类,它是dict
的子类,其键可以被视为项(d[k]
)或属性(d.k
):
class Struct(dict):
def __init__(self,*args, **kwargs):
dict.__init__(self,*args, **kwargs)
self.__dict__ = self # yes, it is tricky
此处的关键是,在致电__dict__
之前,口译员会检查__[gs]etattr__
,因此您甚至不需要覆盖它们。
现在你可以做到:
class Devices(Struct):
pass
devices = Devices()
devices.device = Struct(name='devicename')
devices.device.name = 'anothername'