Reputation: 2509
Let's say you want the object at the end of strings of object names: an example string would be 'first_class.second_class.third_class.id'
, and the list of strings all take the form 'X1object.X2object...XNobject.what_you_want_is_here_object'
.
In every case, you know that there is an active instance of the X1object, whatever its specific name. With the example string, the code has already called an instance of first_class
. You can load first_class
with globals['first_class']
, and generically load X1object
with globals['X1object']
.
What you want is the object (usually a value) at then end of the string. So with the example string, you want the value of id = first_class.second_class.third_class.id
. Is there an easy way to convert the string so that it fetches its end object?
Below is the code I created to handle this problem, but it seems like a brute force approach that fetches each attribute in turn until it finds the last one.
first_class = FirstClass()
first_class = go_do_something_wild_in_first_class(first_class)
...
attribute = 'first_class.second_class.third_class.id'
attribute_pieces = attribute.split('.')
fetch_attribute = lambda attribute, name: \
attribute[name] if attribute == globals() else \
getattr(attribute, name)
for name in attribute_pieces: # I changed the code from using an index to using a name
if name == attribute_pieces[0]:
attribute = fetch_attribute(globals(), name)
else:
attribute = fetch_attribute(attribute, name)
id = attribute
Upvotes: 3
Views: 1231
Reputation: 1121486
You can use reduce()
:
def resolve_object(name):
names = name.split('.')
return reduce(getattr, names[1:], globals()[names[0]])
Here we simply look up names[0]
as a global, then loop over the rest of the names to do a getattr
for each one on the result so far.
Demo:
>>> class Foo(object): pass
...
>>> first_class = Foo()
>>> first_class.second_class = Foo()
>>> first_class.second_class.third_class = Foo
>>> first_class.second_class.third_class.id = 'baz'
>>> resolve_object('first_class.second_class.third_class.id')
'baz'
Upvotes: 4
Reputation: 10353
You should use importlib
attribute = 'first_class.second_class.third_class.id'
attribute_pieces = attribute.split('.')
id = getattr(importlib.import_module('.'.join(attribute_pieces[:-1]), attribute_pieces[-1])
Upvotes: 1
Reputation: 83788
There is a Python library called zope.dottedname which does exactly what you want:
https://pypi.python.org/pypi/zope.dottedname
It resolves arbitrary strings to corresponding objects in Python namespace, including attributes of objects.
Upvotes: 1