I'm trying to define an attribute in a nested class and then access it later using a string or maybe a list of strings. Here's code for what I'm trying to do
class MyNestedClass(object):
def __init__(self):
self.att1 = 5.
class MyClass(object):
def __init__(self):
self.my_nested_inst = MyNestedClass()
my_inst = MyClass()
I want to change the value of my_inst.my_nested_inst.att1 when all I have is a list like this: my_list = ['my_inst','my_nested_inst','att1'].
If I use this:
vars(vars(vars()[my_list[0]])[my_list[1]])[my_list[2]]
This works, but the problem is that I need to extend it to an arbitrary depth of nested instances. I can't figure out a good way to make this work with a for loop. Any help is greatly appreciated.
Also, note that converting a string to a variable name in the global namespace has been well addressed, but none of the answers seem to apply here.
EDIT1: I'll try to explain why I'm doing this, and let me know if I do a poor job of explaining. I am using scipy.optimize.fmin, and I have been using only 4 parameters for optimzation. However, I now want to expand my optimization code to handle an arbitrary number of parameters, some of which are nested attributes several layers into the class/instance hierarchy. I want to be able to create a list or dictionary at the top level to tell fmin how to unpack the parameter array for setting the nested attributes.
解决方案
You can use operator.attrgetter to get nested attributes by specifying an attribute name containing dots (requires Python 2.6+):
After f = attrgetter('date.month'), the call f(b) returns b.date.month.
For convenience, you can create a pair of helper functions:
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)
Here's a complete example (tested with 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.)