3

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
2
  • You want an actual instance of class X? And what is the actual goal? Because there might be an easier solution. Commented Mar 5, 2013 at 16:25
  • i have a list of strings like 'first_class.second_class.third_class.id'. And I want to iterate over the list and return the final object as if I were writing id = first_class.second_class.third_class.id. The input is a string, and the output is the actual object which would be called. Commented Mar 5, 2013 at 16:31

3 Answers 3

4

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'
Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

1

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])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.