2

Imagine a folder structure as follows:

project/
    grandparent.py
    folder1/
        parent.py
        folder2/
            sibling.py
            current.py

If I am in current.py I can import from the other files using relative paths as follows:

from .sibling import *
from ..parent import *

How can I import from grandparent.py ?

(I've tried ...grandparent and ../..grandparent )

lofidevops
  • 15,528
  • 14
  • 79
  • 119

2 Answers2

3

Create a Python Package

As a means to ensure some level of security - so that Python modules cannot access areas where they are not welcome - importing from parents or grandparents is generally prohibited... unless you create a package.

Luckily, in Python, creating a package is crazy-easy. You simply need to add a __init__.py file in each folder/directory that you want to treat as part of the package. And, the __init__.py file doesn't even need to contain anything. You just need the (potentially empty) file to exist.

For instance:

#current.py

from folder1.grandparent import display

display()

#grandparent.py
def display():
    print("grandparent")

# ├── folder1
# │   ├── __init__.py
# │   ├── folder2
# │   │   ├── __init__.py
# │   │   └── folder3
# │   │       ├── __init__.py
# │   │       └── current.py
# │   └── grandparent.py

Next Steps

This is not in the OP's question, but highly related and worth mentioning: If you import a directory instead of a module (file), then you are importing the __init__.py file. E.g.,

import folder1

actually performs an import of the __init__.py file in the folder1 directory.

Lastly, the double-underscore is used so often, it's shortened to dunder. So when speaking, you can say "dunder init" to refer to __init__.py.

Mike Williamson
  • 4,915
  • 14
  • 67
  • 104
ZYYYY
  • 81
  • 4
  • To be clear, if someone is new: @ZYYYY added those `__init__.py` files at each folder level that is part of the package. Those files can be **completely empty**, as long as they exist. By adding them, you have made the package "traversable" and you can import as shown. Final note: with Python 3 in *some cases* you don't need to have the `__init__.py` files present. But please use them; (a) it makes your code more friendly to legacy Python, (b) it is clear to others what is considered part of the package, and (c) even Python 3 cannot fully traverse, like in this grandparent case. – Mike Williamson Jun 27 '18 at 00:44
  • 1
    Does folder1 have to be in sys.path? – bgoodr Jul 01 '18 at 00:30
  • 1
    I tried the answer but it didn't work. But it did work after adding folder 1 to sys.path. Is this a mandatory step? – Ken Lin Mar 27 '20 at 18:21
-2

current.py

import os
import sys
FILE_ABSOLUTE_PATH = os.path.abspath(__file__)  # get absolute filepath
CURRENT_DIR = os.path.dirname(FILE_ABSOLUTE_PATH)  # get directory path of file
PARENT_DIR = os.path.dirname(CURRENT_DIR)  # get parent directory path
BASE_DIR = os.path.dirname(PARENT_DIR)  # get grand parent directory path
# or you can directly get grandparent directory path as below
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

sys.path.append(BASE_DIR)  # append the path to system
import grandparent
from folder1 import parent  # this way you can import files from parent directory too instead of again appending it to system path
Community
  • 1
  • 1
Gahan
  • 4,075
  • 4
  • 24
  • 44
  • Best not to be messing with **actual** path names, but to add the `__init__.py` files, as @ZYYY mentioned above. – Mike Williamson Jun 27 '18 at 00:41
  • @MikeWilliamson It's not messing with actual path, it's the way many modules prefer to use and not to worry about init file. If you look it's just a way to get current/parent directory of a file – Gahan Jun 27 '18 at 05:52