我正在尝试在嵌套类中定义属性,然后使用字符串或字符串列表来访问它。这是我正在尝试做的代码
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如何解压缩参数数组以设置嵌套属性。
答案 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
(正如有人在回答中写的那样,然后他删除了......)也许最容易理解的是递归实现:
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或循环。