通过getattr动态获取dict元素?

时间:2012-02-01 18:19:12

标签: python dictionary getattr

我想动态查询我想要检索的类中的哪些对象。 getattr 似乎就像我想要的那样,它对于类中的顶级对象执行得很好。但是,我还想指定子元素。

class MyObj(object):
    def __init__(self):
        self.d = {'a':1, 'b':2}
        self.c = 3

myobj = MyObj()
val = getattr(myobj, "c")
print val # Correctly prints 3
val = getattr(myobj, "d['a']") # Seemingly incorrectly formatted query
print val # Throws an AttributeError

如何通过字符串获取对象的字典元素?

4 个答案:

答案 0 :(得分:7)

您收到错误的原因是getattr(myobj, "d['a']")在对象上查找名为d['a']的属性,而没有。您的属性名为d,它是一个字典。一旦你有了对字典的引用,然后就可以访问它中的项目。

mydict = getattr(myobj, "d")
val    = mydict["a"]

或者正如其他人所表明的那样,你可以在一步中将它结合起来(我将它显示为两个以更好地说明实际发生的事情):

val = getattr(myobj, "d")["a"]

您的问题暗示您认为对象中字典的项是对象的“子元素”。但是,字典中的项与对象的属性不同。 (getattr()也不适用于o.a之类的东西;它只获取一个对象的一个​​属性。如果那也是一个对象,你想得到一个它的属性,这是另一个getattr()。)

您可以非常轻松地编写一个遍历属性路径的函数(以字符串形式给出)并尝试将每个名称解析为字典键或属性:

def resolve(obj, attrspec):
    for attr in attrspec.split("."):
        try:
            obj = obj[attr]
        except (TypeError, KeyError):
            obj = getattr(obj, attr)
    return obj

这里的基本思想是你采用路径,并且对于路径的每个组件,尝试在类似字典的容器中找到项目或者在对象上找到属性。当你到达路径的尽头时,返回你所拥有的。您的示例是resolve(myobj, "d.a")

答案 1 :(得分:3)

您只需使用方括号来获取字典的元素:

val = getattr(myobj, "d")["a"]

val设置为1

答案 2 :(得分:1)

如果您需要字典项也是动态的,则需要在get的结果上调用getattr

value = getattr(myobj, 'd').get('a')

答案 3 :(得分:1)

感谢Kindall的回答,我发现以下内容适用于叮咬的词典。

class Obj2(object):
    def __init__(self):
        self.d = {'a':'A', 'b':'B', 'c': {'three': 3, 'twothree': (2,3)}}
        self.c = 4

class MyObj(object):
    def __init__(self):
        self.d = {'a':1, 'b':2, 'c': {'two': 2, 'onetwo': (1,2)}}
        self.c = 3
        self.obj2 = Obj2()

    def resolve(self, obj, attrspec):
        attrssplit = attrspec.split(".")
        attr = attrssplit[0]
        try:
            obj = obj[attr]
        except (TypeError, KeyError):
            obj = getattr(obj, attr)
        if len(attrssplit) > 1:
            attrspec = attrspec.partition(".")[2] # right part of the string.
            return self.resolve(obj, attrspec) # Recurse
        return obj

    def __getattr__(self, name):
        return self.resolve(self, name)

# Test  
myobj = MyObj()
print getattr(myobj, "c")
print getattr(myobj, "d.a")
print getattr(myobj, "d.c.two")
print getattr(myobj, "obj2.d.a")
print getattr(myobj, "obj2.d.c.twothree")