Skip to content

ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ

Paths with pathlib

4 min read

"The file is right there, so why can't Python find it?" Almost everyone asks that in their first week with files. By the end of this lesson you'll describe where a file is with a Path, read and write with it in one line, list a folder, and know the real reason behind that FileNotFoundError.

A path is a value

A says where a file is: the folders to go through, then the file's name. Python's pathlib module (one of the modules that come with Python) gives you Path values for them. The / operator joins parts, the same way on every system.

Predict the last line first: what's the suffix of ledger.json?

ውጤቱን ገምቱ

Decide before you look. Guessing wrong is how this sticks.

from pathlib import Path

print(Path("data/ledger.json").suffix)
Pick the output

Python prints

.json

The suffix is the end of the name from the last dot, dot included. If you picked json, you expected the extension without its dot; if you picked ledger, that's the stem, the name without its suffix.

.suffix keeps the dot. Now the rest of what a path can tell you. data/ledger.json is a starting file here:

from pathlib import Path

path = Path("data") / "ledger.json"
print(path)
print(path.name)
print(path.stem)
print(path.parent)
print(path.exists())
print(Path("data/old.json").exists())

In the editor, press Escape then Tab to move on.

ፋይሎች1 starting file

data/ledger.json

[]

On Windows, the first line would print data\ledger.json: / joins with whichever separator the system uses, so you never type backslashes yourself. .name is the last part, .stem is the name without its suffix, and .parent is the folder it's in. .exists() checks whether there's really a file there.

A path is just a description. Making Path("data/old.json") doesn't create anything, which is why .exists() can say False.

Reading and writing in one line

For a whole file at once, a path can read and write for you. It opens the file, does the job, and closes it, so there's no with to write:

from pathlib import Path

path = Path("greeting.txt")
path.write_text("ሰላም\n", encoding="utf-8")
print(path.read_text(encoding="utf-8"))

In the editor, press Escape then Tab to move on.

write_text empties the file first, like mode "w" (lesson 8.1). For adding to a file, or reading line by line, use open() as before: path.open("a", encoding="utf-8") works too.

A path's folders must already exist before you write into them:

The working folder

Here is the reason behind "the file is right there". A path that doesn't start from the top of the disk, like data.json or data/ledger.json, is a relative path. Python looks for it starting from the , also called the current working directory. That's usually the folder your terminal was in when you started the program, not the folder the script is in.

Say Hana's course folder looks like this, and her terminal is in python-course:

python-course/            <- the terminal is here
    ledger/
        ledger.py
        data.json         <- the file she means

She runs python ledger/ledger.py, and ledger.py opens data.json. Python looks in python-course, the working folder, finds nothing, and raises FileNotFoundError, with the file sitting right next to the script. VS Code's Run button often starts in the project's top folder too, so this happens there as well.

ጥያቄ

Hana's data.json is next to ledger.py, but opening it gives FileNotFoundError. Why?

The fix is to start from the script's own location. Python sets __file__ to the full path of the file that's running, so this finds data.json next to the script, whatever the working folder is:

ledger.py
from pathlib import Path
 
DATA_FILE = Path(__file__).parent / "data.json"

In the browser, the working folder is always the script's folder (/home/learner), so the trap can't happen here, but __file__ works the same. Path.cwd() gives the working folder:

from pathlib import Path

print(Path.cwd())
print(Path(__file__))
print(Path(__file__).parent / "data.json")

In the editor, press Escape then Tab to move on.

Listing a folder

.iterdir() gives every path in a folder, and .glob("*.csv") only those whose names fit a pattern, where * stands for any text. The order isn't fixed, so sort them:

from pathlib import Path

folder = Path(".")
for path in sorted(folder.iterdir()):
    print(path.name)
print("---")
for path in sorted(folder.glob("*.csv")):
    print(path.name)

In the editor, press Escape then Tab to move on.

ፋይሎች3 starting files

prices.csv

item,price

notes.txt

Empty file.

sales.csv

day,total

Path(".") is the working folder. main.py is in the list because it's the program itself: the code in the box is saved as main.py before it runs, as a script is on your computer. Change "*.csv" to "*.txt" and run it again.

መልመጃ

Only the text files

Write three small files, a.txt, b.csv, and c.txt, with write_text, then print the names of only the .txt files in the working folder, in order.

Output
a.txt
c.txt

Your code

from pathlib import Path

# Write a.txt, b.csv, and c.txt, then list only the .txt files

In the editor, press Escape then Tab to move on.

መፍትሄውን አሳይ

This is one way to solve it, not the only one. If yours prints the same thing, it works.

from pathlib import Path

for name in ["a.txt", "b.csv", "c.txt"]:
    Path(name).write_text("hello\n", encoding="utf-8")

for path in sorted(Path(".").glob("*.txt")):
    print(path.name)

ዋና ዋና ነጥቦች

  • Path("data") / "ledger.json" builds a path on any system; .name, .stem, .suffix (with its dot), and .parent take it apart.
  • .exists() checks for a real file; read_text and write_text read or write a whole file in one line.
  • A relative path starts from the working folder, not the script's folder: that's why "the file is right there" can still give FileNotFoundError.
  • Path(__file__).parent / "data.json" finds a file next to the script, wherever the program is run from.
  • .iterdir() and .glob("*.txt") list a folder; sort the result.