简体   繁体   中英

Resolving a Python object in global namespace by string look up

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

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'

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM