Reputation: 331
I am currently doing a personal coding project and I am trying to build a module, but I don't know why my structure doesn't work the way it's supposed to:
\mainModule
__init__.py
main.py
\subModule_1
__init__.py
someCode_1.py
someCode_2.py
\subModule_2
__init__.py
otherCode.py
I want to be able to run the following code from main.py
:
>>> from subModule_1 import someCode_1
>>> someCode_1.function()
"Hey, this works!"
>>> var = someCode_2.someClass("blahblahblah")
>>> var.classMethod1()
>>> "blah blah blah"
>>> from subModule2 import otherCode
>>> otherCode("runCode","#ff281ba0")
However, when I try to import someCode_1
, for example, it returns an AttributeError
, and I'm not really sure why. Is it to do with the __init__.py
file?
Minimal, Complete and verifiable (I hope...)
\mainDir
__init__.py # blank file
main.py
\subDir
__init__.py # blank file
codeFile.py
Using this...
#main.py file
import subDir
subDir.codeFile.function()
And this...
#codeFile.py file
def function():
return "something"
...it returns the same problem mentioned above**.
** The exact error is:
Traceback (most recent call last):
File "C:\...\mainDir\main.py", line 2, in <module>
subDir.codeFile.function()
AttributeError: module 'subDir' has no attribute 'codeFile'
Credits to @jonrsharpe: Thanks for showing me how to use Stack Overflow correctly.
Upvotes: 2
Views: 154
Reputation: 15349
When you import subDir
, it does three things:
mainDir/subDir/__init__.py
(i.e. in this case does nothing, because this file is empty)subDir
locally, which will in turn make it an attribute of the mainDir
module;sys.modules
dictionary (because the import
is being performed from a parent module mainDir
, the name is completed to 'mainDir.subDir'
for the purposes of this registration);What it does not do, because it hasn't been told to, is import subDir.codeFile
. Therefore, the code in codeFile.py
has not been run and the name codeFile
has not yet been imported into the namespace of mainDir.subDir
. Hence the AttributeError
when trying to access it. If you were to add the following line to mainDir/subDir/__init__.py
then it would work:
import codeFile
Specifically, this will:
codeFile.py
mainDir.subDir
modulesys.modules
, this time under the name mainDir.subDir.codeFile
.You could also achieve the same effect from higher up the module hierarchy, by saying import subDir, subDir.codeFile
instead of just import subDir
in your mainDir.main
source file.
NB: When you test this from the command line or IDE, make sure that your current working directory (queried by os.getcwd()
, changed using os.chdir(wherever)
) is neither mainDir
nor subDir
. Work from somewhere else—e.g. the parent directory of mainDir
. Working from inside a module will lead to unexpected results.
Upvotes: 1
Reputation: 671
You have two options to make this work.
Either this:
from subdir import codeFile
codeFile.function()
Or:
import subdir.codeFile
subdir.codeFile.function()
Upvotes: 1