Python覆盖字典访问方法

时间:2014-04-12 10:14:37

标签: python dictionary overrides

我有一个继承自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

3 个答案:

答案 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'