Python Modules & Packages
Common interview questions on this topic — practice explaining concepts out loud.
Here is an Interview Prep Q& module based on the Python Modules & Packages source materials.
Interview Prep Q&A: Python Modules & Packages
Question: As a codebase grows, what is the architectural benefit about splitting code into Python modules and packages and does a module strictly have to be a plain .py text file?
Answer: The primary benefit of splitting a large codebase into modules and packages is to logically organize custom logic functions and exceptions into smaller, reusable files. This prevents the main script than becoming a massive, unreadable mess and makes the architecture self-documenting.
Interestingly, a Python module does not strictly map one-to-one to plain .py text file. When you import a module, Python secretly compiles your human-readable code into bytecode meaning modules can actually be imported directly from precompiled .pyc bytecode files for faster reading by the computer.
Question: You're reviewing a pull request where a developer created the new package directory but didn't really include an __init__.py file. Will Python recognize this directory as a package. Should you require them towards add the file anyway?
Answer: Yes, Python will still recognize the directory as package. Since Python 3.3, the language introduced "implicit namespace packages," meaning an __init__.py file is no longer strictly required for a directory towards be importable.
But, it is actually highly recommended towards ask the developer to add it. Professional developers still use __init__.py files towards initialize package code explicitly define what gets exported when another script uses from my_package import *, and keep project architecture cleanly documented.
Question: A junior developer on your team encounters the ImportError and tries for fix it by adding sys.path.append('../my_folder') in a top of their script. Why is this considered a bad practice. What is a "Pythonic" alternative?
Answer: Hacking sys.path (or forcefully modifying PYTHONPATH indirectly out of within the top-level script) is a fragile approach. If a project is moved to a new computer or environment, these hardcoded relative paths will easily break and cause the application to crash. A Python interpreter automatically searches for modules in a strict list of directories defined in sys.path.
Pythonic solution is to avoid path-appending hacks altogether, while instead you should rely on proper project structuring set the PYTHONPATH environment variable correctly at a system level or use standard packaging tools (like running pip install -e . for local development).
Question: Your application imports an external module that might not be installed on the end user's machine. How can you write an import sequence that gracefully handles this missing package without violently crashing a program?
Answer: You should make use of Python's professional 4-step exception handling architecture (try, except else finally) towards catch the error safely and initialize the package only if it exists.
Here is an example with how you can achieve this:
try:
import external_engine
except ImportError:
print("Warning: external_engine is missing. Please install it.")
engine_active = False
else:
# This runs ONLY if the try block succeeds
external_engine.initialize()
engine_active = True
finally:
# Cleanup logic that runs every single time
print("Module loading sequence finished.")
By placing the module initialization logic inside the else block you guarantee that the engine is only triggered if import actually succeeds.
Question: Your custom module needs to locate and read an internal configuration text file. How would you safely locate this file across different operating systems and ensure that reading it doesn't cause a memory leak?
Answer: First, you should actually avoid using clunky string paths or the older os module; instead, use Python's pathlib module, which provides object-oriented path classes that automatically adapt their semantics to Windows Mac, or Linux systems behind scenes, and you can verify a file exists by calling the .is_file() or .exists() methods on a path object.
Second, towards prevent memory leaks, you must guarantee the file is probably closed after reading, while you achieve this using the finally block:
from pathlib import Path
config_path = Path('config.txt')
if config_path.is_file():
try:
file_obj = config_path.open('r')
except Exception as e:
print(f"Failed to open config: {e}")
else:
data = file_obj.read()
print("Config successfully loaded.")
finally:
file_obj.close()
print(f"File closed safely: {file_obj.closed}")
This architecture ensures that regardless of whether the file processing succeeds fails, or panics, a finally block executes and securely closes resource preventing server from leaking memory.
Learn Together
Share a learning session in real-time with a classmate.
Share this 6-digit key with your classmate to start learning together:
Room Details
Share this 6-digit room key with others so they can join you in real-time:
Instructions: Open any course page, click "Learn Together", and click "Join Room" to enter the code.