6

我想动态查询我想检索的类中的哪些对象。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

4 回答 4

8

您收到错误的原因是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")

于 2012-02-01T18:59:44.713 回答
3

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

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

那将设置val1

于 2012-02-01T18:21:23.857 回答
2

如果您还需要字典项是动态的,则需要调用get以下结果getattr

value = getattr(myobj, 'd').get('a')
于 2012-02-01T18:53:55.440 回答
1

感谢 Kindall 的回答,我发现以下内容适用于 dict 键。

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")
于 2012-02-05T18:59:52.693 回答