104

I have a directory with a number of .py files in it. each file defines some classes. I also have an empty __init__.py in the directory.

For example:

myproject
    __init__.py
    mymodule
        __init__.py
        api.py
        models.py
        views.py

I am trying to import mymodule and access the classes defined in all these files:

from myproject import mymodule

print mymodule.api.MyClass 

It gives me an error saying that mymodule has no attribute api. Why? And why I can access just one of the files (models.py) and not the others?

In [2]: dir(banners)
Out[2]:
['__builtins__',
 '__doc__',
 '__file__',
 '__name__',
 '__package__',
 '__path__',
 'models']
Savir
  • 17,568
  • 15
  • 82
  • 136
akonsu
  • 28,824
  • 33
  • 119
  • 194

4 Answers4

112

The problem is submodules are not automatically imported. You have to explicitly import the api module:

import myproject.mymodule.api
print myproject.mymodule.api.MyClass

If you really insist on api being available when importing myproject.mymodule you can put this in myproject/mymodule/__init__.py:

import myproject.mymodule.api

Then this will work as expected:

from myproject import mymodule

print mymodule.api.MyClass 
Rob Wouters
  • 15,797
  • 3
  • 42
  • 36
  • Isn't this a bit cumbersome? Is there a way to switch on importing of sub-modules (with the full qualifying names, e.g foo.bar.baz) by default? – Amir Rosenfeld May 01 '19 at 15:20
  • I'm fine doing the full import, but in the rest of the code I'd like to drop `myproject` and refer to `mymodule.api` which does not seem to be possible? – Alper Aug 16 '19 at 10:03
  • @AmirRosenfeld No, there is no such way, and there **cannot possibly** be such a way, because *the file system does not actually dictate* where the sub-modules are or what all their names are. Python allows for huge amounts of customization of the import system. Aside from that, it would be a terrible default behaviour, because in most cases it would slow down all the top-level imports in order to import huge amounts of code that isn't actually used later. – Karl Knechtel Apr 28 '23 at 20:08
  • @Alper Using relative imports within the package will save you a lot of typing. More complex renamings are possible, but they require a proper understanding of the import system which is probably beyond the scope of even a separate Stack Overflow Q&A, let alone the comments section. – Karl Knechtel Apr 28 '23 at 20:11
42

Also check whether you didn't name your python file the same as the module you are trying to import.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Olaf
  • 587
  • 4
  • 6
  • 9
    Yes, this is a strange piece of Python rubric, that the filename must be different from the module name. Be warned! – CharlesW Dec 13 '20 at 13:18
  • 5
    Oh wow, that's a difficult one to google! – PatrickT Oct 17 '21 at 11:13
  • The file name **does not** need to differ from the module name. In fact, the file name **for the module that you are implementing**, by definition, dictates the module name. This is a **completely unrelated** problem that comes up when you want to import a **different module** from the current file, but the current file has the same name as the other module you want to import. The problem is that **every Python source code file defines a module**, whether or not you intend for it to be `import`ed. The modules defined by source code files can, therefore, attempt to import themselves. – Karl Knechtel Apr 28 '23 at 20:03
  • The canonical for this problem is [Importing a library from (or near) a script with the same name raises "AttributeError: module has no attribute" or an ImportError or NameError](/q/36250353). – Karl Knechtel Apr 28 '23 at 20:04
2

Modules don't work like that.

from myproject.mymodule import api
print api.MyClass
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • I know I can do that. Is it possible to do using the dotted names? – akonsu Jan 17 '12 at 17:47
  • 2
    @akonsu, simply do `import myproject.mymodule.api` then and access it through `myproject.mymodule.api.MyClass`. – Rob Wouters Jan 17 '12 at 17:50
  • well, i think this is a question about the language in general, not about how I can get my code to work. I am curious as to whether this can be achieved. can I make it access my classes through 'mymodule.api...' without the leading 'myproject'? – akonsu Jan 17 '12 at 17:53
  • you could do `import myproject.mymodule as mymodule` but it seems confusing to me – Matt Jan 17 '12 at 18:00
-4

You need an __init__.py in the myproject directory too. So your module structure should be:

myproject
    __init__.py
    mymodule
        __init__.py
        api.py
        models.py
        views.py
Akash
  • 277
  • 2
  • 11
  • 11
    That's exactly the module structure in the question... – SenhorLucas Sep 11 '20 at 19:19
  • Aside from that, since Python 3.3 empty `__init__.py` files **are not required** to set up directories as packages (although they do influence the lookup order for absolute imports). A missing `__init__.py` **is not** the reason for a relative import failing in modern Python. – Karl Knechtel Apr 28 '23 at 20:13