So, I'm trying to learn a little bit more of how the __init__.py
file works. It supposedly give you the ability to import a dictionaries as a package. I use VS code. My test1.py
run as expected, but the test2.py
file dosen't. It gives me the error: ModuleNotFoundError: No module named 'subdir'
. I run the scripts from test1.py
and test2.py
.
I've looked up many resources, but I haven't got it too work yet. In test2.py
, I try to import the Apple
class from class1.py
and the Banana
class from class2.py
(both as a package). test2.py
is trying to import from a parent directory which is probably what's causing the problem, but how can I make it work?
directory structure
init_file_testing/
test1.py
subdir/
__init__.py
class1.py
class2.py
subdir2/
test2.py
test1.py
from subdir import Apple
from subdir import Banana
a = Apple("red")
print(a)
b = Banana("yellow")
print(b)
__init__.py
from subdir.test_class1 import Apple
from subdir.test_class2 import Banana
class1.py
class Apple:
def __init__(self, color):
self.color = color
def __str__(self):
return f"The color of the apple is {self.color}"
class2.py
class Banana:
def __init__(self, color):
self.color = color
def __str__(self):
return f"The color of the banana is {self.color}"
test2.py
import sys
sys.path.append("..")
from subdir import Apple
from subdir import Banana
a = Apple("red")
print(a)
b = Banana("yellow")
print(b)
CodePudding user response:
If you run python test1.py
and it works, that implies (unless you used some other technique to set up the sys.path
) you are in the init_file_testing
folder, and that folder is on the path that is searched for Python modules. If you want to from subdir import
something, then you need that folder on your path - because that is the folder that contains the subdir
package.
If you run python test2.py
and the file is found, that implies (similar logic) you are in subdir2
. Hacking the path with sys.path.append("..")
does not help, because that puts the subdir
folder on the path, but you need the init_file_testing
folder instead. In relative terms, that is sys.path.append("../..")
.
However, if you are willing to use relative paths as part of a hack to make this work, then why not just use relative imports instead? This is how you are intended to work within packages.
That looks like:
test1.py
from .subdir import Apple, Banana
__init__.py
from .class1 import Apple
from .class2 import Banana
test2.py
from ..subdir import Apple, Banana
Then, you only need to ensure that the package root (init_file_testing
) is on the module search path, no matter which module you start from; and that you start from either the root folder or from outside the package folders (which you should do anyway). One easy way to ensure the path is set up is by installing your package in a virtual environment (which is the recommended approach for development anyway). You can also do it with the PYTHONPATH
environment variable.