11

How to import nested package using the "as" shorthand?

This question is similar to importing a module in nested packages only the nesting is within the same .py file, not across folders.

In foo.py (All python files are in the same package, and are version 3.4):

class Foo:
    class Bar:
        ...

I can access these subclasses in another .py file:

from . import foo
...
bar = foo.Foo.Bar()

What I would like to do:

from . import foo.Foo.Bar as Bar  # DOES NOT WORK: "unresolved reference" error.
...
bar = Bar()  # saves typing.
bar2 = Bar()
...

Is there a way to do this?

Community
  • 1
  • 1
Kevin Kostlan
  • 3,311
  • 7
  • 29
  • 33

1 Answers1

16

There is little point in nesting Python classes; there is no special meaning attached to doing so other than nesting the namespaces. There rarely is any need to do so. Just use modules instead if you need to produce additional namespaces.

You cannot directly import a nested class; you can only import module globals, so Foo in this case. You'd have to import the outer-most class and create a new reference:

from .foo import Foo
Bar = Foo.Bar
del Foo  # remove the imported Foo class again from this module globals

The del Foo is entirely optional. The above does illustrate why you'd not want to nest classes to begin with.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Interesting point. I sometimes have custom exceptions as class members of the class (the only class) that throws them. Is this discouraged too? – Hyperboreus Apr 05 '14 at 19:17
  • @Hyperboreus: not really; Django uses this on generated models. In that case the per-model exception is a subclass of a more generic exception you can import directly though. – Martijn Pieters Apr 05 '14 at 19:18
  • @Hyperboreus: However, most beginning developers using nested classes don't really know what they are doing; I mostly discourage the use on those grounds. – Martijn Pieters Apr 05 '14 at 19:21
  • 3
    there is a point in having inner classes: contextualizing code. for example, an error that belongs to a certain interface. you're documenting code by the structure. – Luís Soares Nov 26 '21 at 20:03
  • "there is little point in nesting python classes". A million languages implementing custom namespaces disagree with you. What is your solution to organizing the code? You said most beginning developers using nested classes don't really know what they are doing. What are they doing? I am failing to see the point you are making here. OP wants to organize their code in a nested way, which they have, and want to import it with a one-liner or have a similarly elegant implementation. Provide a solution, or back up your claim and provide an alternative? – MuhsinFatih Jan 22 '22 at 01:49
  • @MuhsinFatih you can’t. Nested classes have their uses (the `Meta` pattern in schema DSLs like Django or Marshmallow), but *you can’t import nested attributes*, only top-level names. Which is why this is an anti-pattern in Python. – Martijn Pieters Jan 22 '22 at 01:57
  • @MuhsinFatih in Java, nesting classes is used as a means of inner state sharing where normally that state is encapsulated and fenced off. It’s not used for namespacing! Python doesn’t have such a concept. If you want namespacing, use packages and modules, not nested classes. – Martijn Pieters Jan 22 '22 at 01:59
  • @MuhsinFatih Note that other languages doing something *doesn’t matter*. I’m simply stating facts here: Python doesn’t treat nested classes as special and you can’t import the nested objects. I already have a solution in my answer, if you want namespaces, use modules. – Martijn Pieters Jan 22 '22 at 02:03
  • @MartijnPieters Thanks for elaborating. Imo it would be nice if I can organize *some* code in one file rather than multiple modules (or files). Like for example, I have "constants.py" where I have error codes and strings and more. I'd like to be able to do something like `from constants.error_codes.uploader import upload_failed` (I just made up this example) without having to create a nested folder structure. I used namespaces in a number of languages before so that's the kind of use case where I imagine this being useful – MuhsinFatih Jan 22 '22 at 02:13