Python
Importing Classes
Directory Structure
Python Programming
Code Organization

How to import the class within the same directory or sub directory?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Import problems in Python usually come from project layout and execution style, not from the import statement itself. A class import that works in one terminal command can fail in another if package boundaries are unclear. This guide shows reliable patterns for importing classes from the same directory and from subdirectories without path hacks.

Core Sections

Same Directory Import

When two files are siblings, import by module name. Keep file names descriptive and avoid names that shadow standard library modules.

text
project/
  main.py
  user_service.py
python
1# user_service.py
2class UserService:
3    def get_display_name(self, username: str) -> str:
4        return f"User: {username}"
python
1# main.py
2from user_service import UserService
3
4service = UserService()
5print(service.get_display_name("mark"))

Run from the project directory:

bash
python main.py

This is simple and works well for small scripts.

Subdirectory Import with a Package

For larger codebases, place related modules in a package directory and add __init__.py.

text
1project/
2  app.py
3  services/
4    __init__.py
5    user_service.py
python
1# app.py
2from services.user_service import UserService
3
4print(UserService().get_display_name("mark"))

The __init__.py file makes intent explicit for tools and readers, and keeps behavior consistent across environments.

Prefer Absolute Imports Inside Projects

Absolute imports are easier to understand in larger teams because they show full location context.

text
1project/
2  src/
3    myapp/
4      __init__.py
5      main.py
6      services/
7        __init__.py
8        user_service.py
python
1# src/myapp/main.py
2from myapp.services.user_service import UserService
3
4print(UserService().get_display_name("mark"))

From project root:

bash
python -m myapp.main

Module mode is important. It executes code with package context, which keeps imports stable.

When Relative Imports Are Appropriate

Relative imports are useful inside package internals when modules move together.

python
1# src/myapp/services/__init__.py
2from .user_service import UserService
3
4__all__ = ["UserService"]
python
1# src/myapp/main.py
2from myapp.services import UserService
3
4print(UserService().get_display_name("mark"))

Do not run src/myapp/main.py directly as a plain script if it depends on package-relative behavior. Use module mode from the project root.

Avoid sys.path Mutation as a Default Fix

Many import issues are temporarily "fixed" by appending paths at runtime. That tends to hide structural problems and creates environment-specific bugs.

python
# discouraged pattern
# import sys
# sys.path.append("../")

A better fix is to:

  1. define a real package structure
  2. run modules with python -m
  3. keep tests and app entrypoints aligned

Handling Circular Imports

If two modules import each other, you can get partially initialized module errors. The clean solution is to move shared types or interfaces into a third module.

text
1src/myapp/
2  models.py
3  services.py
4  contracts.py

models.py and services.py both import from contracts.py instead of importing each other. This breaks the dependency loop and keeps import order predictable.

Quick Validation Checklist

Before you assume Python is wrong, verify:

  • the working directory used to run the command
  • file and package names are unique and not shadowing stdlib
  • package directories include __init__.py where expected
  • you are running package code with module mode

These checks catch most import failures quickly.

Common Pitfalls

  • Running a package file directly and expecting relative imports to behave as if module mode were used.
  • Naming a file typing.py, json.py, or another stdlib name that shadows built-in modules.
  • Mixing absolute and ad hoc path-based imports in the same project.
  • Using runtime sys.path edits that work locally but fail in CI or production.
  • Creating circular imports instead of extracting shared code to a separate module.

Summary

  • Same-directory imports are straightforward with sibling module names.
  • Subdirectory imports should use explicit package structure and __init__.py.
  • Prefer absolute imports and run entrypoints with python -m.
  • Treat sys.path mutation as a temporary workaround, not architecture.
  • Resolve circular imports by redesigning dependencies, not by import-order tricks.

Course illustration
Course illustration

All Rights Reserved.