使用dict访问Python中嵌套的类实例

时间:2012-03-01 20:55:35

标签: python namespaces nested-attributes

我正在尝试在嵌套类中定义属性,然后使用字符串或字符串列表来访问它。这是我正在尝试做的代码

class MyNestedClass(object):
    def __init__(self):
        self.att1 = 5.

class MyClass(object):
    def __init__(self):
        self.my_nested_inst = MyNestedClass()

my_inst = MyClass()

我希望更改my_inst.my_nested_inst.att1的值,只要我拥有的是这样的列表:my_list = ['my_inst','my_nested_inst','att1']

如果我使用它:

vars(vars(vars()[my_list[0]])[my_list[1]])[my_list[2]]

这很有效,但问题是我需要将它扩展到任意深度的嵌套实例。我无法找到一个好的方法来使用for循环工作。任何帮助是极大的赞赏。

另外,请注意,在全局命名空间中将字符串转换为变量名称已得到很好的解决,但这些答案似乎都不适用于此处。

EDIT1:我会试着解释为什么我这样做,如果我的解释工作做得不好,请告诉我。我使用scipy.optimize.fmin,我一直只使用4个参数进行优化。但是,我现在想扩展我的优化代码来处理任意数量的参数,其中一些是嵌套属性,在层/实例层次结构中有几层。我希望能够在顶层创建一个列表或字典,告诉fmin如何解压缩参数数组以设置嵌套属性。

3 个答案:

答案 0 :(得分:6)

您可以使用operator.attrgetter通过指定包含点的属性名称来获取嵌套属性(需要Python 2.6 +):

  

f = attrgetter('date.month')之后,来电f(b)会返回b.date.month

为方便起见,您可以创建一对辅助函数:

def get_nested_attr(vars_dict, attrs):
    inst = vars_dict[attrs[0]]
    return operator.attrgetter('.'.join(attrs[1:]))(inst)

def set_nested_attr(vars_dict, attrs, value):
    setattr(get_nested_attr(vars_dict, attrs[0:-1]), attrs[-1], value)

这是一个完整的例子(使用Python 2.7.2测试):

import operator

class MyNestedClass(object):
    def __init__(self):
        self.att1 = 5.

class MyClass(object):
    def __init__(self):
        self.my_nested_inst = MyNestedClass()

def get_nested_attr(vars_dict, attrs):
    inst = vars_dict[attrs[0]]
    return operator.attrgetter('.'.join(attrs[1:]))(inst)

def set_nested_attr(vars_dict, attrs, value):
    setattr(get_nested_attr(vars_dict, attrs[0:-1]), attrs[-1], value)


my_inst = MyClass()
my_list = ['my_inst','my_nested_inst','att1']

assert(my_inst.my_nested_inst.att1 == 5.)
set_nested_attr(vars(), my_list, 10.)
assert(my_inst.my_nested_inst.att1 == 10.)

答案 1 :(得分:3)

假设)中的最后一个vars...是拼写错误,您可以选择多种方式来实现以下功能:

def namespace(names):
    """
        returns vars(vars(..vars(locals())[names[0]])..[names[-2]])[names[-1]]
    """
  • 使用reduce(正如有人在回答中写的那样,然后他删除了......)
  • 递归函数
  • 明确使用堆栈和while循环的函数

也许最容易理解的是递归实现:

def namespace(myList):
    if len(myList)==0:
        return locals()
    else:
        oneLevelUp = namespace(myList[:-1])
        return vars(oneLevelUp[myList[-1]])

reduce实现同样优雅。以下是reduce的工作原理:

>>> functools.reduce(lambda a,b:[a,b], range(4), 'x')
[[[['x', 0], 1], 2], 3]

实施:

def namespace(myList):
    return reduce(lambda ns,item:vars(ns[item]), myList, locals())

答案 2 :(得分:0)

修改:正如评论中指出的那样,attrgetter不能像我使用它一样工作。你必须  使用reduce或循环。