我有一个从dict类继承的类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
所以你的答案基本上是完整的。你可以定义你想要的结构类型:
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'
基本上只需嵌套属性查找字典。
通常,要访问字典值,请使用dictionary[key]
而不是dictionary.key
。在第一种情况下,属性方式有效,因为您覆盖了__getattr__
而不是__getitem__
。这就是为什么它只适用于类,而不适用于内部字典。
现在,要访问__getitem__
中的字典(__getattr__
表示属性,就像dict.keys
中单词keys
表示属性一样),您需要小心一点。您需要调用dictionary类的__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'})
。
BTW:请注意,__init__
中有一个错误。__init__
中的self = {'device':{'name':'device_name'}}
行实际上没有任何作用。(它将字典放在局部变量self
中,但一旦退出函数,该变量就会消失。)
您应该使用更改对象本身的操作。即:
def __init__(self):
self['device'] = {'name':'device_name'}
您可以使用这个棘手的类,它是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
这里的关键是,解释器在调用__[gs]etattr__
之前会检查__dict__
,所以您甚至不需要覆盖它们。
现在你可以做:
class Devices(Struct):
pass
devices = Devices()
devices.device = Struct(name='devicename')
devices.device.name = 'anothername'