Ana içeriğe geç

Dosya Sistemi İşlemleri için Python’da pathlib Kullanımına Kapsamlı Bir Rehber

Dosya sistemiyle etkileşim için yol nesnelerini, yol bileşenlerini ve yaygın yol işlemlerini inceleyerek Python pathlib’in os modülüne göre avantajlarını keşfedin.
· 9 dk. oku

Yapay Zeka ile Keşfedin

Yakın zamana kadar, Python’da dosya sistemiyle çalışmak epey zordu. Geliştiriciler, girdi olarak uzun dizgiler gerektirdiği için hataya açık olan hatalı dosya yollarıyla sıkça mücadele ediyordu. Ayrıca, farklı işletim sistemleri arasındaki tutarsızlıklar nedeniyle kodlarının sık sık bozulduğunu bildiriyorlardı.

Neyse ki, Python 3.4 sürümünde geliştiriciler standart kütüphaneye pathlib modülünü eklediler. pathlib, uzun zamandır beklenen nesne yönelimli yaklaşımla dosya sistemi yollarını ele almak için zarif bir çözüm sunar ve aynı zamanda platformdan bağımsız davranışı garanti eder.

Bu kapsamlı eğitim, dosya sisteminizle günlük etkileşimlerinizi desteklemek için pathlib modülünün özelliklerini öğretecek. pathlib kullanarak verimli iş akışlarından ve kolay veri erişiminden faydalanacaksınız. pathlib yıllar içinde önemli ölçüde olgunlaştı ve biz de sizin yerinize güncel kaldık. Hadi başlayalım.

Python os Modülü vs. pathlib

Python 3.4’ten önce, dosya yollarını ele almanın daha geleneksel yolu os modülünü kullanmaktı. os modülü bir zamanlar oldukça etkili olsa da artık yaşını belli etmeye başladı.

Bir veri bilimi görevinden yola çıkarak pathlib’in benzersiz değerini gösterebiliriz: Belirli bir dizin ve tüm alt dizinleri içinde tüm png dosyalarını nasıl buluruz?

Eğer os modülünü kullansaydık, şu kodu yazabilirdik:

import os
dir_path = "/home/user/documents"
files = [
os.path.join(dir_path, f)
for f in os.listdir(dir_path)
if os.path.isfile(os.path.join(dir_path, f)) and f.endswith(".png")
]

Bu kod png dosyalarını bulma işini anlık olarak çözse de os modülünün birkaç büyük dezavantajını ortaya koyuyor. Öncelikle, bu görece basit işlem için kod uzun ve neredeyse okunaksız. İkinci olarak, kodumuz liste üreteçleri bilgisini varsayıyor; bu her zaman beklenmemeli. Üçüncü olarak, kod dize işlemlerine dayanıyor ve bunlar hataya açık. Tüm bunlara ek olarak, kod pek özlü değil. 

Eğer bunun yerine pathlib modülünü kullansaydık, kodumuz çok daha basit olurdu. Belirttiğimiz gibi, pathlib dosya sistemi yollarını ele almak için nesne yönelimli bir yaklaşım sunar. Şuna bakın:

from pathlib import Path

# Create a path object
dir_path = Path(dir_path)

# Find all text files inside a directory
files = list(dir_path.glob("*.png"))

Bu nesne yönelimli programlama, kodu nesneler ve onların etkileşimleri etrafında organize eder; böylece daha modüler, yeniden kullanılabilir ve bakımı kolay kodlar yazılır. Nesne yönelimli programlamaya aşina değilseniz, bunu Nesne Yönelimli Python Programlama kursumuz ile öğrenmeye değer. 

Python’da Yol (Path) Nesneleriyle Çalışma

pathlib kütüphanesi, dosya sistemi yollarını yapılandırılmış ve platformdan bağımsız şekilde temsil eden Path nesneleri etrafında döner.

Bu eğitimde daha önce, pathlib modülünden Path sınıfını geçerli ad alanımıza şu kod satırıyla getirmiştik:

from pathlib import Path

pathlib’ten Path sınıfını çağırdıktan sonra, dizgilerden, diğer Path nesnelerinden, geçerli çalışma dizininden ve ana dizinden Path nesneleri oluşturabiliriz.

Her birine sırayla bakalım.

Dizgilerden yol nesneleri oluşturma

Bir dosya sistemi yolunu temsil eden bir dizgeyi bir değişkene geçirerek bir Path nesnesi oluşturabiliriz. Bu, dosya yolunun dizge gösterimini bir Path nesnesine dönüştürür.

file_path_str = "data/union_data.csv"

data_path = Path(file_path_str)

Diğer yol nesnelerinden yol nesneleri oluşturma

Mevcut Path nesneleri, yeni yollar oluşturmak için yapı taşı olarak kullanılabilir. 

Bunu, bir temel yolu, bir veri dizinini ve bir dosya adını tek bir dosya yolunda birleştirerek yaparız. Path nesnelerimizi genişletmek için uygun yerlerde eğik çizgi kullanmayı unutmamalıyız.

base_path = Path("/home/user")
data_dir = Path("data")

# Combining multiple paths
file_path = base_path / data_dir / "prices.csv"  
print(file_path)
'/home/user/data/prices.csv'

Geçerli çalışma dizininden yol nesneleri oluşturma

Burada, Path.cwd() yöntemini kullanarak geçerli çalışma dizinini cwd değişkenine atıyoruz. Ardından betiğimizin çalıştığı geçerli çalışma dizininin yolunu alabiliriz. 

cwd = Path.cwd()

print(cwd)
'/home/bexgboost/articles/2024/4_april/8_pathlib'

Ana çalışma dizininden yol nesneleri oluşturma

Ana dizinimizi ek alt dizinlerle birleştirerek bir yol oluşturabiliriz. Burada ana dizinimizi "downloads" ve "projects" alt dizinleriyle birleştiriyoruz. 

home = Path.home()

home / "downloads" / "projects"
PosixPath('/home/bexgboost/downloads/projects')

Önemli bir not: Path sınıfı, yol doğrulama, dizin veya dosya oluşturma gibi herhangi bir dosya sistemi işlemini tek başına gerçekleştirmez. Yolları temsil etmek ve bunlarla işlem yapmak için tasarlanmıştır. Dosya sistemiyle gerçekten etkileşim kurmak (varlık kontrolü, dosya okuma/yazma) için Path nesnelerinin özel yöntemlerini kullanmamız ve bazı ileri düzey durumlarda os modülünden yardım almamız gerekir.

Python’da Yol Bileşenleriyle Çalışma

Dosya yolu öznitelikleri, bir dosya sistemindeki dosya ve dizinleri tanımlamaya ve yönetmeye yardımcı olan çeşitli özellikler ve bileşenlerdir. Tıpkı bir fiziksel adresin sokak numarası, şehir, ülke ve posta kodu gibi bölümleri olması gibi, bir dosya sistemi yolu da daha küçük bileşenlere ayrılabilir. pathlib, nokta gösterimi ile yol özniteliklerini kullanarak bu bileşenlere erişmemizi ve bunları yönetmemizi sağlar.

Kök dizinle çalışma

Kök, bir dosya sistemindeki en üst dizindir. Unix benzeri sistemlerde eğik çizgi (/) ile gösterilir. Windows’ta genellikle iki nokta üst üste ile izlenen bir sürücü harfidir; örneğin C:.

image_file = home / "downloads" / "midjourney.png"

image_file.root
'/'

Üst (parent) dizinle çalışma

Üst dizin, geçerli dosya veya dizini içerir; mevcut dizin ya da dosyaya göre bir seviye yukarıdadır. 

image_file.parent
PosixPath('/home/bexgboost/downloads')

Dosya adıyla çalışma

Bu öznitelik, uzantı dahil olmak üzere tüm dosya adını bir dizge olarak döndürür.

image_file.name
'midjourney.png'

Dosya uzantısıyla (suffix) çalışma

Suffix özniteliği, nokta dahil dosya uzantısını bir dizge olarak (veya uzantı yoksa boş bir dizge) döndürür.

image_file.suffix
'.png'

Dosya kökü (stem) ile çalışma

Stem, dosya adını uzantı olmadan döndürür. Dosyaları farklı biçimlere dönüştürürken stem ile çalışmak faydalı olabilir.

image_file.stem
'midjourney'

Not: Mac’te dosya yolları büyük/küçük harfe duyarlıdır; dolayısıyla /Users/username/Documents ile /users/username/documents farklı olur. 

pathlib parts özniteliği

.parts özniteliğini kullanarak bir Path nesnesini bileşenlerine ayırabiliriz.

image_file.parts
('/', 'home', 'bexgboost', 'downloads', 'midjourney.png')

pathlib parents özniteliği

parents özniteliği, bir yineleyici döndürür ve bu bileşenleri Path nesnelerine çevirir. 

list(image_file.parents)
[PosixPath('/home/bexgboost/downloads'),
PosixPath('/home/bexgboost'),
PosixPath('/home'),
PosixPath('/')]

pathlib ile Yaygın Yol İşlemleri

Path nesneleri, dizinler ve içerikleriyle verimli şekilde etkileşime olanak tanıyan birçok yönteme sahiptir. En yaygın işlemlerden bazılarını nasıl yapacağımıza bakalım.

Dizin listeleme

iterdir() yöntemi, bir klasördeki tüm dosyalar ve alt dizinler üzerinde yineleme yapmanıza olanak tanır. Bir dizindeki tüm dosyaları işlemek veya her bir girdi üzerinde işlem yapmak için özellikle kullanışlıdır.

cwd = Path.cwd()
 for entry in cwd.iterdir():
# Process the entry here
...
# print(entry)

iterdir() bir yineleyici döndürdüğünden, girdiler döngü boyunca ihtiyaç duyuldukça alınır.

is_dir() yöntemi

is_dir() yöntemi, yol bir dizini işaret ediyorsa True, aksi halde False döndürür.

for entry in cwd.iterdir():
   if entry.is_dir():
      print(entry.name)
.ipynb_checkpoints
data
images

is_file() yöntemi

.is_file() yöntemi, yol bir dosyayı işaret ediyorsa True, aksi halde False döndürür.

for entry in cwd.iterdir():
   if entry.is_file():
      print(entry.suffix)
.ipynb
.txt

exists() yöntemi

Path nesneleri sadece yolları temsil ettiğinden, bazen bir yolun var olup olmadığını .exists() yöntemiyle kontrol etmeniz gerekir:

.exists() yöntemi bir yolun var olup olmadığını kontrol eder. Bu kullanışlıdır çünkü Path nesneleri, dosya sisteminde gerçekte mevcut olabilecek veya olmayabilecek dosya ve dizinleri temsil edebilir.

image_file.exists()
False

Yol oluşturma ve silme

pathlib, dosya ve dizin oluşturma ve silme işlevleri de sunar. Nasıl yapıldığına bakalım.

mkdir() yöntemi

mkdir() yöntemi belirtilen yolda yeni bir dizin oluşturur. Varsayılan olarak, geçerli çalışma dizininde dizin oluşturur.

from pathlib import Path

data_dir = Path("new_data_dir")

# Create the directory 'new_data_dir' in the current working directory
data_dir.mkdir()

mkdir(parents=True) yöntemi

mkdir(parents=True) yöntemi, bazı üst dizinlerin mevcut olmayabileceği bir dizin yapısı oluşturmak istediğinizde özellikle kullanışlıdır. parents=True ayarı, gerekli tüm üst dizinlerin yol boyunca oluşturulmasını sağlar.

sub_dir = Path("data/nested/subdirectory")

# Create 'data/nested/subdirectory', even if 'data' or 'nested' don't exist
sub_dir.mkdir(parents=True)

Unutmayın, mkdir() aynı adda bir dizin zaten varsa bir hata fırlatır.

Path('data').mkdir()
FileExistsError: [Errno 17] File exists: 'data'

unlink() yöntemi

unlink() yöntemi, Path nesnesinin temsil ettiği bir dosyayı kalıcı olarak siler. Hata almamak için bu yöntemi çalıştırmadan önce dosyanın var olup olmadığını kontrol etmeniz önerilir.

to_delete = Path("data/prices.csv")

if to_delete.exists():
   to_delete.unlink()
   print(f"Successfully deleted {to_delete.name}")
Successfully deleted prices.csv

rmdir() yöntemi

rmdir() yöntemi boş bir dizini kaldırır. rmdir()’ın yalnızca boş dizinleri kaldırmak için çalıştığını unutmayın. Boş olmayan bir dizini silmenin en kolay yolu shutil kütüphanesini veya terminali kullanmaktır.

empty_dir = Path("new_data_dir")

empty_dir.rmdir()

Not: unlink() veya rmdir() kullanırken dikkatli olun; sonuçları kalıcıdır.

Gelişmiş Yol İşleme

Şimdi pathlib kullanarak bazı gelişmiş yol işleme kavramlarına ve bunların pratikte nasıl uygulanacağına geçelim.

Göreli ve mutlak yollar

Sıkça karşımıza çıktıkları için, önce mutlak ve göreli yollar arasındaki farkları anlayalım.

Göreli yollar

Göreli yollar, adından da anlaşılacağı gibi, bir dosya veya dizinin konumunu geçerli dizine göre belirtir. Projeniz içinde kısadır ve esnektir, ancak çalışma dizinini değiştirirseniz kafa karıştırıcı olabilirler.

Örneğin, geçerli çalışma dizinimde midjourney.png dosyasının bulunduğu bir images klasörü var.

image = Path("images/midjourney.png")

image
PosixPath('images/midjourney.png')

Yukarıdaki kod şu an çalışıyor, ancak kullandığım defteri (notebook) farklı bir konuma taşırırsam, images klasörü defterle birlikte taşınmadığı için bu parça bozulur.

Mutlak yollar

Mutlak yollar, dosya sisteminin kökünden itibaren bir dosya veya dizinin tam konumunu belirtir. Geçerli dizinden bağımsızdırlar ve sistemdeki herhangi bir kullanıcı için net bir referans noktası sunarlar.

image_absolute = Path("/home/bexgboost/articles/2024/4_april/8_pathlib/images/midjourney.png")

image_absolute
PosixPath('/home/bexgboost/articles/2024/4_april/8_pathlib/images/midjourney.png')

Görüldüğü gibi, özellikle iç içe ağaç yapılarının olduğu karmaşık projelerde mutlak yollar epey uzun olabilir. Bu nedenle, çoğu kişi daha kısa olan göreli yolları tercih eder.

resolve yöntemi

pathlib, resolve() yöntemiyle göreli yolları mutlak yollara dönüştürme imkânı sunar.

relative_image = Path("images/midjourney.png")

absolute_image = relative_image.resolve()

absolute_image
PosixPath('/home/bexgboost/articles/2024/4_april/8_pathlib/images/midjourney.png')

Tersi de mümkün: Elimizde bir mutlak yol varsa, bunu bir başvuru dizinine göre göreli yola çevirebiliriz.

relative_path = Path.cwd()

absolute_image.relative_to(relative_path)
PosixPath('images/midjourney.png')

Globbing

Globbing’i açıklamak için, yazının başında verdiğimiz örneğe dönelim; belirli bir dizindeki tüm png dosyalarını bulmak için kod yazmıştık.

files = list(dir_path.glob("*.png"))

pathlib, herhangi bir dizinde belirli bir desene uyan dosyaları verimli şekilde aramak için yerleşik .glob() modülünü kullanır. Bu yöntem, benzer ada veya uzantıya sahip dosyaları işlerken çok kullanışlıdır.

glob yöntemi, girdi olarak joker karakterler içeren bir desen dizgesi alır ve eşleşen Path nesnelerini ihtiyaç halinde üreten bir yineleyici döndürür:

  • *: Sıfır veya daha fazla karakteri eşleştirir.

  • ?: Herhangi bir tek karakteri eşleştirir.

  • []: Köşeli parantez içindeki bir karakter aralığını eşleştirir (ör. [a-z] herhangi bir küçük harfi eşleştirir).

Örnek olarak, makaleler dizinimdeki tüm Jupyter defterlerini bulmayı deneyelim.

articles_dir = Path.home() / "articles"

# Find all scripts
notebooks = articles_dir.glob("*.ipynb")

# Print how many found
print(len(list(notebooks)))
0

.glob() yöntemi hiçbir defter bulmadı; ilk bakışta şaşırtıcı gelebilir çünkü 150’den fazla makale yazdım. Bunun nedeni, .glob()’ın yalnızca verilen dizin içinde arama yapması, alt dizinlerde yapmamasıdır.

Bunu özyinelemeli bir aramayla çözebiliriz; bunun için benzer sözdizimine sahip rglob() yöntemini kullanmamız gerekir:

notebooks = articles_dir.rglob("*.ipynb")

print(len(list(notebooks)))
357

Bu kez kodumuz tüm 357 dosyayı buldu.

Dosyalarla Çalışma

Gördüğümüz gibi, Path nesneleri dosyaları sadece temsil eder, üzerlerinde işlem yapmaz. Ancak, yaygın dosya işlemleri için bazı yöntemlere sahiptir. Bu bölümde bunları nasıl kullanacağımızı göreceğiz.

Dosya okuma

Birçok Python uygulamasında dosya içeriği okumak temel bir işlemdir. pathlib, dosyaları metin veya ham bayt olarak okumak için kullanışlı kısayol yöntemleri sağlar.

read_text() yöntemi, bir metin dosyasının içeriğini okumamıza ve dosyayı kapatmamıza olanak tanır.

file = Path("file.txt")

print(file.read_text())
This is sample text.

İkili dosyalar için ise read_bytes() yöntemini kullanabiliriz.

image = Path("images/midjourney.png")

image.read_bytes()[:10]
b'\x89PNG\r\n\x1a\n\x00\x00'

read_* yöntemlerini kullanırken hata yönetiminin önemli olduğunu unutmayın:

nonexistent_file = Path("gibberish.txt")

try:
   contents = nonexistent_file.read_text()
except FileNotFoundError:
   print("No such thing.")
No such thing.

Dosya yazma

Dosyaya yazmak, dosya okumak kadar kolaydır. Dosya yazmak için write_text() yöntemine sahibiz.

file = Path("file.txt")

file.write_text("This is new text.")
17
file.read_text()
'This is new text.'

Görüldüğü gibi, write_text() yöntemi metni üzerine yazar. write_text() için ekleme modu olmasa da, dosyanın sonuna metin eklemek için read_text() ve write_text() yöntemlerini birlikte kullanabiliriz.

old_text = file.read_text() + "\n"
final_text = "This is the final text."

# Combine old and new texts and write them back
file.write_text(old_text + final_text)

print(file.read_text())
This is new text.

This is the final text.

write_bytes() benzer şekilde çalışır. Bunu göstermek için önce midjourney.png görselini yeni bir adla çoğaltalım.

original_image = Path("images/midjourney.png")

new_image = original_image.with_stem("duplicated_midjourney")

new_image
PosixPath('images/duplicated_midjourney.png')

with_stem() yöntemi, farklı bir dosya adıyla (suffix aynı kalır) bir dosya yolu döndürür. Bu sayede özgün bir görseli okuyup içeriğini yeni bir görsele yazabiliriz. 

new_image.write_bytes(original_image.read_bytes())
1979612

Dosya yeniden adlandırma ve taşıma

with_stem() işlevine ek olarak, pathlib daha kapsamlı yeniden adlandırma için rename() yöntemini sunar. 

file = Path("file.txt")

target_path = Path("new_file.txt")

file.rename(target_path)
PosixPath('new_file.txt')

rename(), bir dizge veya başka bir yol nesnesi olabilen bir hedef yol alır.

Dosyaları taşımak için, yine bir hedef yol alan replace() işlevini kullanabilirsiniz:

# Define the file to be moved
source_file = Path("new_file.txt")

# Define the location to put the file
destination = Path("data/new/location")

# Create the directories if they don't exist
destination.mkdir(parents=True)

# Move the file
source_file.replace(destination / source_file.name)
PosixPath('data/new/location/new_file.txt')

Boş dosya oluşturma

pathlib, touch yöntemiyle boş dosyalar oluşturmamıza olanak tanır:

# Define new file path
new_dataset = Path("data/new.csv")

new_dataset.exists()
False
new_dataset.touch()

new_dataset.exists()
True

touch yöntemi aslında bir dosyanın değişiklik zamanını güncellemek için tasarlanmıştır; bu nedenle mevcut dosyalarda da kullanılabilir.

original_image.touch()

Bir dosya adını ileride kullanmak üzere ayırmanız, ancak şu anda yazacak içeriğiniz olmaması gerektiğinde, boş bir dosya oluşturmak için touch kullanabiliriz. Bu yöntem Unix’teki touch terminal komutundan esinlenilmiştir.

İzinler ve dosya sistemi bilgileri

Son olarak, .stat() yöntemiyle dosya özelliklerine nasıl erişeceğimizi öğreneceğiz. os ile aşinaysanız, bu yeni yöntemin çıktısının os.stat() ile aynı olduğunu fark edeceksiniz.

image_stats = original_image.stat()

image_stats
os.stat_result(st_mode=33188, st_ino=1950175, st_dev=2080, st_nlink=1, st_uid=1000, st_gid=1000, st_size=1979612, st_atime=1714664562, st_mtime=1714664562, st_ctime=1714664562)

Dosya boyutunu da nokta gösterimiyle alabiliriz.

image_size = image_stats.st_size

# File size in megabytes
image_size / (1024**2)
1.8879051208496094

Sonuç

Python 3.4’te pathlib modülünün tanıtılması, geliştiriciler için dosya sistemiyle çalışmayı önemli ölçüde basitleştirdi. Dosya yollarını ele almak için nesne yönelimli bir yaklaşım sunarak, pathlib dosya sistemi yollarını temsil etmek için yapılandırılmış ve anlaşılır bir yol sağlar. pathlib ayrıca platform bağımsızlığı sunar; yani farklı işletim sistemleri arasında yol ayraçlarını tutarlı biçimde ele alır, böylece kodumuz yeni bir makinede bozulmaz. Son olarak, gördüğümüz üzere pathlib yaygın dosya sistemi işlemleri için özlü ve ifade gücü yüksek çok sayıda yöntem sunar. 

Unutmayın, pathlib Python’daki güçlü yerleşik kütüphanelerden yalnızca biridir. Python ile Veri Bilimci Kariyer Patikası, Python Programlama Yetenek Patikası ve Veri Bilimi için Python’a Giriş kurslarımızı alarak, güçlü bir Python programcısı olmak için geniş bir yerleşik kütüphane yelpazesine hâkim olacaksınız. 

Okuduğunuz için teşekkürler!


Bexruz (Bex) Tuychiev

Yazar

Bexruz (Bex) Tuychiev

2 yılı aşkın deneyime sahip bir veri bilimi içerik üreticisiyim ve Medium’da en büyük takipçi kitlelerinden birine sahibim. Yapay zekâ ve makine öğrenimi üzerine, biraz da alaycı bir üslupla yazılmış, ayrıntılı makaleler kaleme almayı seviyorum; çünkü onları biraz daha az sıkıcı hale getirmek için bir şeyler yapmak gerekiyor. 130’un üzerinde makale ve bir de DataCamp kursu ürettim; bir diğeri de hazırlık aşamasında. İçeriklerim 5 milyondan fazla kişi tarafından görüldü; bunların 20 bini Medium ve LinkedIn’de takipçim oldu. 

Konular

İlgili