Search code examples
pythonpython-importinstantiationinner-classes

How does one use python's __import__() and getattr() to correctly to instantiate nested classes?


I have the following code in module xyz:

Class Outer:
   Class Nested:
       pass

I can successfully instantiate Outer objects as follows

module = __import__("xyz", fromlist=[''])
the_class = getattr(module, "Outer")
instance = the_class()

However, when I replace "Outer" with "Outer.Nested" I get:

AttributeError: module 'xyz' has no attribute Outer.Nested

How can one make this work?

I should perhaps clarify that the above code is being used to instantiate classes whose type is unknown until runtime. Obviously I am not looking for instance = Outer.Nested().


Solution

  • Two ways to do this, suppose you have a string representing attribute access and a nested object:

    >>> from types import SimpleNamespace
    >>> module = SimpleNamespace(foo=SimpleNamespace(bar=SimpleNamespace(baz='tada!')))
    >>> module
    namespace(foo=namespace(bar=namespace(baz='tada!')))
    

    The first is to basically parse the string yourself by splitting and using getattr in a loop (or even, reduce!):

    >>> from functools import reduce
    >>> reduce(getattr, "foo.bar.baz".split('.'), module)
    'tada!'
    

    Which is just equivalent to:

    >>> result = module
    >>> for attr in "foo.bar.baz".split("."):
    ...     result = getattr(result, attr)
    ...
    >>> result
    'tada!'
    

    Or use the built-in functools.attrgetter factory function as a one-off:

    >>> import operator
    >>> operator.attrgetter("foo.bar.baz")(module)
    'tada!'