When handling file or directory paths in a program, concatenating directory names and file names to create a single path string is a frequent operation. While it is possible to simply add strings (+) or use the join method with /, this can cause environment-dependent bugs because the path separator differs by OS (Windows uses \, macOS/Linux uses /).
In Python, using the join() function from the standard library os.path module allows you to join paths appropriately according to the execution environment’s OS. This article explains the basic usage of os.path.join() and the important “path reset specification” to be aware of when joining.
1. Basic Usage of os.path.join()
os.path.join() joins multiple path elements (strings) passed as arguments using the separator suitable for that OS.
Syntax:
import os
joined_path = os.path.join(part1, part2, ...)
Specific Usage Example
Here is an example of creating a full file path by joining a data directory, a user ID, and a filename.
import os
# Elements to join
base_dir = "application_data"
sub_dir = "user_settings"
filename = "config.json"
# Join paths
full_path = os.path.join(base_dir, sub_dir, filename)
print(f"Joined Result: {full_path}")
Output (Windows):
Joined Result: application_data\user_settings\config.json
Output (macOS / Linux):
Joined Result: application_data/user_settings/config.json
As shown, the appropriate separator is automatically inserted according to the execution environment.
2. [Important] Behavior with Absolute Paths (Reset)
There is a specification that requires the most caution when using os.path.join(). That is: “If a string starting with a separator (/ or \) (root path/absolute path) is included in the middle of the elements to be joined, all elements before it are discarded.”
Example of Unintended Joining
Let’s assume a case where you inadvertently added a / to the subdirectory specification when trying to create a backup destination path.
import os
# Backup root directory
backup_root = "backup_storage"
# Yearly folder (Mistakenly added a leading / here)
year_folder = "/2025"
# Filename
log_file = "access.log"
# Execute join
result_path = os.path.join(backup_root, year_folder, log_file)
print(f"Root: {backup_root}")
print(f"Element: {year_folder}")
print("-" * 20)
print(f"Result: {result_path}")
Output (macOS / Linux):
Root: backup_storage
Element: /2025
--------------------
Result: /2025/access.log
We expected backup_storage/2025/access.log, but because year_folder started with /, Python interpreted this as “a new absolute path starts here” and ignored the leading backup_storage.
Workaround
You must ensure that the parts to be joined (filenames or subdirectory names) do not contain a leading separator. If there is a possibility that the input value contains one, remove it using .lstrip("/") or similar methods before joining.
# Remove the leading separator before joining
safe_path = os.path.join(backup_root, year_folder.lstrip("/"), log_file)
print(f"Corrected Result: {safe_path}")
Output:
Corrected Result: backup_storage/2025/access.log
Supplement: Using the pathlib Module
In Python 3.4 and later, using the more modern pathlib module is also recommended. Here, you can join paths intuitively using the / operator.
from pathlib import Path
path = Path("application_data") / "user_settings" / "config.json"
print(path)
Summary
- Use
os.path.join()to join paths. It handles the differences in separators between OSs. - If a string starting with
/or\(absolute path format) is included in the middle of the arguments, the path preceding it is ignored. - Be careful not to attach a separator to the beginning of each part to be joined.
