Python重写字典访问方法



我有一个从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'

最新更新