Mengapa Anda harus menggunakan pathlib

Dari penerjemah: Halo, Habr! Saya hadir untuk Anda terjemahan artikel Mengapa Anda harus menggunakan pathlib dan kelanjutannya, Tidak benar-benar, pathlib bagus . Banyak perhatian sekarang sedang dibayarkan untuk fitur Python baru seperti asyncio, the: = operator, dan pengetikan opsional. Pada saat yang sama, tidak begitu signifikan (meskipun :: sebut inovasi serius bahasa tidak berubah menjadi inovasi serius) berisiko untuk radar, tetapi inovasi yang sangat berguna dalam bahasa. Secara khusus, pada habr artikel yang ditujukan untuk subjek, saya tidak menemukan (kecuali satu paragraf di sini ), oleh karena itu saya memutuskan untuk memperbaiki situasi.


Ketika saya menemukan modul pathlib yang baru beberapa tahun yang lalu, saya memutuskan dari bawah pikiran saya bahwa itu hanya versi berorientasi objek yang agak canggung dari modul os.path . Saya salah. pathlib benar-benar luar biasa !


Pada artikel ini saya akan mencoba jatuh cinta pada pathlib . Saya harap artikel ini pathlib Anda untuk menggunakan pathlib dalam situasi apa pun terkait bekerja dengan file dengan Python .



Bagian 1


os.path canggung


Modul os.path selalu menjadi apa yang kami gunakan ketika datang ke jalur Python. Pada prinsipnya, ada semua yang Anda butuhkan, tetapi seringkali itu tidak terlihat terlalu elegan.


Haruskah saya mengimpornya seperti itu?


 import os.path BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates') 

Atau lebih?


 from os.path import abspath, dirname, join BASE_DIR = dirname(dirname(abspath(__file__))) TEMPLATES_DIR = join(BASE_DIR, 'templates') 

Mungkin fungsi join memiliki nama yang terlalu umum, dan kita harus melakukan sesuatu seperti ini:


 from os.path import abspath, dirname, join as joinpath BASE_DIR = dirname(dirname(abspath(__file__))) TEMPLATES_DIR = joinpath(BASE_DIR, 'templates') 

Bagi saya, semua opsi di atas sepertinya tidak terlalu nyaman. Kami meneruskan string ke fungsi yang mengembalikan string yang kami lewatkan ke fungsi berikutnya yang bekerja dengan string. Kebetulan mereka semua mengandung jalan, tetapi mereka masih hanya garis.


Menggunakan string untuk input dan output dalam fungsi os.path sangat tidak nyaman karena Anda harus membaca kode dari dalam ke luar. Saya ingin mengonversi panggilan ini dari bersarang menjadi berurutan. Inilah yang memungkinkan Anda untuk melakukan pathlib !


 from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent TEMPLATES_DIR = BASE_DIR.joinpath('templates') 

Modul os.path membutuhkan pemanggilan fungsi bersarang, tetapi pathlib memungkinkan kita untuk membuat rantai panggilan berurutan ke metode dan atribut kelas Path dengan hasil yang setara.


Saya tahu apa yang Anda pikirkan: berhenti, objek Path ini tidak sama dengan sebelumnya, kami tidak lagi beroperasi di jalur path! Kami akan kembali ke masalah ini nanti (petunjuk: dalam hampir semua situasi, kedua pendekatan ini dapat dipertukarkan).


os kelebihan beban


Modul os.path klasik dirancang untuk bekerja dengan jalur. Tetapi setelah Anda ingin melakukan sesuatu dengan path (misalnya, membuat direktori), Anda perlu mengakses modul lain, sering os .


os berisi banyak utilitas untuk bekerja dengan file dan direktori: mkdir , getcwd , chmod , stat , remove , rename , rmdir . Juga chdir , link , walk , listdir , makedirs , renames , removedirs , removedirs unlink , symlink . Dan banyak hal yang tidak terkait dengan sistem file sama sekali: fork , getenv , putenv , getlogin , getlogin , system , ... Beberapa lusin hal lagi yang tidak akan saya sebutkan di sini.


Modul os dirancang untuk berbagai tugas; ini adalah kotak dengan segala sesuatu yang berkaitan dengan sistem operasi. Ada banyak kegunaan dalam os , tetapi tidak selalu mudah dinavigasi: sering perlu untuk menggali sedikit ke dalam modul sebelum Anda menemukan apa yang Anda butuhkan.


pathlib mentransfer sebagian besar fungsi sistem file ke objek Path .


Berikut adalah kode yang membuat src/__pypackages__ dan mengganti nama file .editorconfig kami menjadi src/.editorconfig :


 import os import os.path os.makedirs(os.path.join('src', '__pypackages__'), exist_ok=True) os.rename('.editorconfig', os.path.join('src', '.editorconfig')) 

Berikut adalah kode yang mirip menggunakan Path


 from pathlib import Path Path('src/__pypackages__').mkdir(parents=True, exist_ok=True) Path('.editorconfig').rename('src/.editorconfig') 

Perhatikan bahwa contoh kode kedua lebih mudah dibaca, karena diatur dari kiri ke kanan - ini semua berkat rangkaian metode.


Jangan lupakan glob


Tidak hanya os dan os.path berisi metode yang terkait dengan sistem file. Perlu juga disebutkan tentang glob , yang tidak bisa disebut tidak berguna.


Kita dapat menggunakan fungsi glob.glob untuk mencari file dengan pola tertentu:


 from glob import glob top_level_csv_files = glob('*.csv') all_csv_files = glob('**/*.csv', recursive=True) 

Modul pathlib juga menyediakan metode serupa:


 from pathlib import Path top_level_csv_files = Path.cwd().glob('*.csv') all_csv_files = Path.cwd().rglob('*.csv') 

Setelah beralih ke modul pathlib , kebutuhan untuk glob menghilang sepenuhnya : semua yang Anda butuhkan sudah merupakan bagian integral dari objek Path


pathlib membuat hal-hal sederhana menjadi lebih mudah


pathlib menyederhanakan banyak situasi sulit, tetapi juga membuat beberapa cuplikan kode sederhana menjadi lebih mudah .


Ingin membaca semua teks dalam satu file atau lebih?


Anda dapat membuka file, membaca konten, dan menutup file menggunakan blok with :


 from glob import glob file_contents = [] for filename in glob('**/*.py', recursive=True): with open(filename) as python_file: file_contents.append(python_file.read()) 

Atau Anda dapat menggunakan metode read_text pada objek Path dan menghasilkan daftar untuk mendapatkan hasil yang sama dalam satu ekspresi:


 from pathlib import Path file_contents = [ path.read_text() for path in Path.cwd().rglob('*.py') ] 

Tetapi bagaimana jika Anda perlu menulis ke file?


Begini tampilannya menggunakan open :


 with open('.editorconfig') as config: config.write('# config goes here') 

Atau Anda dapat menggunakan metode write_text :


 Path('.editorconfig').write_text('# config goes here') 

Jika karena alasan tertentu Anda perlu menggunakan open , baik sebagai manajer konteks atau untuk preferensi pribadi, Path menyediakan metode open sebagai alternatif:


 from pathlib import Path path = Path('.editorconfig') with path.open(mode='wt') as config: config.write('# config goes here') 

Atau, dimulai dengan Python 3.6, Anda bisa melewati Path Anda langsung untuk open :


 from pathlib import Path path = Path('.editorconfig') with open(path, mode='wt') as config: config.write('# config goes here') 

Objek jalur membuat kode Anda lebih jelas


Apa yang ditunjukkan oleh variabel-variabel berikut? Apa arti dari artinya?


 person = '{"name": "Trey Hunner", "location": "San Diego"}' pycon_2019 = "2019-05-01" home_directory = '/home/trey' 

Setiap variabel menunjuk ke sebuah garis. Tetapi masing-masing dari mereka memiliki arti yang berbeda: yang pertama adalah JSON, yang kedua adalah tanggal, dan yang ketiga adalah path file.


Representasi objek ini sedikit lebih berguna:


 from datetime import date from pathlib import Path person = {"name": "Trey Hunner", "location": "San Diego"} pycon_2019 = date(2019, 5, 1) home_directory = Path('/home/trey') 

Objek JSON dapat dideserialisasikan ke dalam kamus, tanggal dapat secara asli direpresentasikan menggunakan datetime.date , dan objek path file dapat direpresentasikan sebagai Path


Menggunakan objek Path membuat kode Anda lebih eksplisit. Jika Anda ingin bekerja dengan tanggal, Anda menggunakan date . Jika Anda ingin bekerja dengan jalur file, gunakan Path .


Saya bukan pendukung OOP yang sangat besar. Kelas menambahkan lapisan abstraksi ekstra, dan abstraksi terkadang cenderung mempersulit sistem daripada menyederhanakannya. Pada saat yang sama, saya percaya bahwa pathlib.Path adalah abstraksi yang bermanfaat . Cukup cepat, itu menjadi keputusan yang diterima.


Berkat PEP 519 , Path menjadi standar untuk bekerja dengan paths. Pada saat Python 3.6, sebagian besar metode os , shutil , os.path bekerja dengan benar dengan objek-objek ini. Anda dapat beralih ke pathlib , transparan untuk basis kode Anda!


Apa yang hilang di pathlib ?


Meskipun pathlib keren, itu tidak komprehensif. Pasti ada beberapa kemungkinan yang ingin saya sertakan dalam modul .


Hal pertama yang terlintas dalam pikiran adalah kurangnya metode jalur yang setara dengan shutil . Meskipun Anda bisa meneruskan Path sebagai parameter shutil untuk menyalin / menghapus / memindahkan file dan direktori, Anda tidak bisa menyebutnya sebagai metode pada objek Path .


Jadi, untuk menyalin file, Anda perlu melakukan sesuatu seperti ini:


 from pathlib import Path from shutil import copyfile source = Path('old_file.txt') destination = Path('new_file.txt') copyfile(source, destination) 

Juga tidak ada analog dari metode os.chdir . Ini berarti bahwa Anda perlu mengimpornya jika Anda perlu mengubah direktori saat ini:


 from pathlib import Path from os import chdir parent = Path('..') chdir(parent) 

Juga tidak ada yang setara dengan fungsi os.walk . Meskipun Anda dapat menulis fungsi Anda sendiri dalam semangat walk tanpa terlalu banyak kesulitan.


Saya berharap bahwa suatu hari objek pathlib.Path akan berisi metode untuk beberapa operasi yang disebutkan. Tetapi bahkan dalam skenario ini, saya merasa jauh lebih mudah menggunakan pathlib dengan sesuatu yang lain daripada menggunakan os.path dan yang lainnya .


Apakah selalu perlu menggunakan pathlib ?


Dimulai dengan Python 3.6, Paths bekerja hampir di mana saja Anda menggunakan string . Jadi saya tidak melihat alasan untuk tidak menggunakan pathlib jika Anda menggunakan Python 3.6 dan di atasnya.


Jika Anda menggunakan versi Python 3 yang lebih lama, Anda bisa kapan saja membungkus objek Path dalam panggilan str untuk mendapatkan string jika Anda perlu kembali ke negara baris. Ini tidak terlalu elegan, tetapi berfungsi:


 from os import chdir from pathlib import Path chdir(Path('/home/trey')) #   Python 3.6+ chdir(str(Path('/home/trey'))) #      

Bagian 2. Jawaban untuk pertanyaan.


Setelah bagian pertama diterbitkan, beberapa orang memiliki beberapa pertanyaan. Seseorang berkata bahwa saya membandingkan pathlib os.path dan pathlib tidak jujur. Beberapa mengatakan bahwa menggunakan os.path tertanam dalam komunitas Python sehingga beralih ke perpustakaan baru akan memakan waktu yang sangat lama. Saya juga melihat beberapa pertanyaan tentang kinerja.


Pada bagian ini, saya ingin mengomentari masalah ini. Ini dapat dianggap sebagai perlindungan pathlib dan sedikit surat cinta untuk PEP 519 .


Bandingkan os.path dan pathlib jujur


Pada bagian terakhir, saya membandingkan dua fragmen kode berikut:


 import os import os.path os.makedirs(os.path.join('src', '__pypackages__'), exist_ok=True) os.rename('.editorconfig', os.path.join('src', '.editorconfig')) 

 from pathlib import Path Path('src/__pypackages__').mkdir(parents=True, exist_ok=True) Path('.editorconfig').rename('src/.editorconfig') 

Ini mungkin tampak seperti perbandingan yang tidak adil, karena menggunakan os.path.join pada contoh pertama menjamin penggunaan pembatas yang benar pada semua platform, yang tidak saya lakukan pada contoh kedua. Faktanya, semuanya sudah beres, karena Path secara otomatis menormalkan pemisah path


Kita dapat membuktikan ini dengan melihat konversi objek Path ke string di Windows:


 >>> str(Path('src/__pypackages__')) 'src\\__pypackages__' 

Tidak ada bedanya apakah kita menggunakan metode joinpath , tanda '/' di garis path, / operator (fitur bagus Path ), atau meneruskan argumen individual ke konstruktor Path, kita mendapatkan hasil yang sama:


 >>> Path('src', '.editorconfig') WindowsPath('src/.editorconfig') >>> Path('src') / '.editorconfig' WindowsPath('src/.editorconfig') >>> Path('src').joinpath('.editorconfig') WindowsPath('src/.editorconfig') >>> Path('src/.editorconfig') WindowsPath('src/.editorconfig') 

Contoh terakhir menyebabkan beberapa kebingungan dari orang-orang yang menyarankan bahwa pathlib tidak cukup pintar untuk mengganti / dengan \ dalam string path. Untungnya, semuanya beres!


Dengan objek Path , Anda tidak perlu lagi khawatir tentang arah garis miring: tentukan semua jalur Anda menggunakan / , dan hasilnya akan dapat diprediksi untuk platform apa pun.


Anda tidak perlu khawatir tentang normalisasi jalan.


Jika Anda menjalankan Linux atau Mac, sangat mudah untuk secara tidak sengaja menambahkan bug ke kode Anda yang hanya memengaruhi pengguna Windows. Jika Anda tidak secara cermat memantau penggunaan os.path.join dan \ atau os.path.normcase untuk mengonversi garis miring menjadi yang cocok untuk platform saat ini, Anda dapat menulis kode yang tidak akan berfungsi dengan benar di Windows .


Berikut adalah contoh bug khusus Windows:


 import sys import os.path directory = '.' if not sys.argv[1:] else sys.argv[1] new_file = os.path.join(directory, 'new_package/__init__.py') 

Selain itu, kode tersebut akan berfungsi dengan benar di mana-mana:


 import sys from pathlib import Path directory = '.' if not sys.argv[1:] else sys.argv[1] new_file = Path(directory, 'new_package/__init__.py') 

Sebelumnya, programmer bertanggung jawab untuk menyatukan dan menormalkan jalur, seperti pada Python 2, programmer bertanggung jawab untuk memutuskan di mana harus menggunakan unicode daripada byte. Ini bukan lagi tugas Anda - Path menyelesaikan semua masalah seperti itu untuk Anda.


Saya tidak menggunakan Windows, dan saya tidak punya komputer Windows. Tetapi banyak orang hebat yang akan menggunakan kode saya kemungkinan besar akan menggunakan Windows, dan saya ingin semuanya bekerja dengan benar untuk mereka.


Jika ada kemungkinan kode Anda akan berjalan di Windows, Anda harus serius mempertimbangkan beralih ke pathlib .


Jangan khawatir tentang normalisasi : tetap gunakan Path ketika datang ke path file.


Kedengarannya keren, tapi saya memiliki perpustakaan pihak ketiga yang tidak menggunakan pathlib !


Anda memiliki basis kode besar yang berfungsi dengan string sebagai path. Mengapa beralih ke pathlib jika itu berarti semuanya harus ditulis ulang?


Bayangkan Anda memiliki fungsi berikut:


 import os import os.path def make_editorconfig(dir_path): """Create .editorconfig file in given directory and return filename.""" filename = os.path.join(dir_path, '.editorconfig') if not os.path.exists(filename): os.makedirs(dir_path, exist_ok=True) open(filename, mode='wt').write('') return filename 

Fungsi mengambil direktori dan membuat file .editorconfig , sesuatu seperti ini:


 >>> import os.path >>> make_editorconfig(os.path.join('src', 'my_package')) 'src/my_package/.editorconfig' 

Jika Anda mengganti garis dengan Path , semuanya akan berfungsi juga:


 >>> from pathlib import Path >>> make_editorconfig(Path('src/my_package')) 'src/my_package/.editorconfig' 

Tapi ... bagaimana caranya?


os.path.join menerima objek Path (sejak Python 3.6). Hal yang sama dapat dikatakan tentang os.makedirs .
Bahkan, fungsi open built-in menerima Path , shutil menerima Path dan segala sesuatu di perpustakaan standar yang digunakan untuk menerima string sekarang harus bekerja dengan Path dan string.


Kita harus berterima kasih kepada PEP 519 untuk ini , yang menyediakan kelas abstrak os.PathLike dan mengumumkan bahwa semua utilitas os.PathLike untuk bekerja dengan path file sekarang harus bekerja dengan string dan Path .


Tetapi perpustakaan favorit saya memiliki Path, lebih baik dari standar!


Anda mungkin sudah menggunakan perpustakaan pihak ketiga yang menyediakan implementasi Path -nya, yang berbeda dari yang standar. Mungkin Anda lebih menyukainya.


Sebagai contoh, django -viron , path.py , plumbum , dan visidata masing-masing berisi objek Path mereka sendiri. Beberapa perpustakaan ini lebih tua dari pathlib , dan memutuskan untuk mewarisi dari str sehingga mereka dapat diteruskan ke fungsi yang mengharapkan string sebagai path. Berkat PEP 519, mengintegrasikan perpustakaan pihak ketiga ke dalam kode Anda akan lebih mudah, dan tanpa perlu warisan dari str .


Mari kita bayangkan bahwa Anda tidak ingin menggunakan pathlib , karena Path adalah objek yang tidak dapat diubah, dan Anda benar-benar ingin mengubah pathlib . Dengan PEP 519, Anda dapat membuat versi Path terbaik yang bisa berubah-ubah. Untuk melakukan ini, cukup terapkan metode __fspath__


Implementasi Path pun yang ditulis sendiri sekarang dapat berfungsi dengan fungsi bawaan Python yang mengharapkan path file. Bahkan jika Anda tidak suka pathlib , fakta keberadaannya merupakan nilai tambah yang besar untuk perpustakaan pihak ketiga dengan Path mereka sendiri


Tapi pathlib.Path dan str tidak tercampur, kan?


Anda mungkin berpikir: ini semua, tentu saja, hebat, tetapi akankah pendekatan ini dengan kadang-kadang-line-dan-kadang-kadang jalan menambahkan beberapa kompleksitas pada kode saya?


Jawaban atas pertanyaan ini adalah ya, sampai batas tertentu. Tetapi masalah ini memiliki solusi yang cukup sederhana.


PEP 519 menambahkan beberapa hal lain selain PathLike : pertama, ini adalah cara untuk mengubah PathLike apa pun menjadi string, dan kedua, itu adalah cara untuk mengubah PathLike apa pun menjadi Path .


Mari kita ambil dua objek - string dan Path (atau apa pun dengan metode fspath ):


 from pathlib import Path import os.path p1 = os.path.join('src', 'my_package') p2 = Path('src/my_package') 

Fungsi os.fspath menormalkan kedua objek dan mengubahnya menjadi string:


 >>> from os import fspath >>> fspath(p1), fspath(p2) ('src/my_package', 'src/my_package') 

Dalam hal ini, Path dapat mengambil kedua objek ini menjadi sebuah konstruktor dan mengubahnya menjadi Path :


 >>> Path(p1), Path(p2) (PosixPath('src/my_package'), PosixPath('src/my_package')) 

Ini berarti Anda dapat mengonversi hasil make_editorconfig kembali ke Path jika perlu:


 >>> from pathlib import Path >>> Path(make_editorconfig(Path('src/my_package'))) PosixPath('src/my_package/.editorconfig') 

Meskipun, tentu saja, solusi terbaik adalah menulis ulang make_editorconfig menggunakan pathlib .


pathlib terlalu lambat


Saya telah melihat beberapa kali tentang kinerja pathlib . Itu benar - pathlib bisa lambat. Membuat ribuan objek Path dapat secara signifikan mempengaruhi perilaku program.


Saya memutuskan untuk mengukur kinerja pathlib dan os.path di komputer saya menggunakan dua program berbeda yang mencari semua file .py di direktori saat ini


Ini adalah versi os.walk :


 from os import getcwd, walk extension = '.py' count = 0 for root, directories, filenames in walk(getcwd()): for filename in filenames: if filename.endswith(extension): count += 1 print(f"{count} Python files found") 

Dan ini adalah versi dengan Path.rglob :


 from pathlib import Path extension = '.py' count = 0 for filename in Path.cwd().rglob(f'*{extension}'): count += 1 print(f"{count} Python files found") 

Menguji kinerja program yang bekerja dengan sistem file adalah tugas yang rumit, karena waktu operasi dapat berubah cukup banyak. Saya memutuskan untuk menjalankan setiap skrip 10 kali dan membandingkan hasil terbaik untuk setiap program.


Kedua program menemukan 97507 file di direktori tempat saya menjalankannya. Yang pertama bekerja dalam 1,914 detik, yang kedua selesai dalam 3,430 detik.


Ketika saya mengatur parameter extension='' , program-program ini menemukan sekitar 600.000 file, dan perbedaannya meningkat. Program pertama bekerja dalam 1,888 detik, dan yang kedua dalam 7,485 detik.


Jadi, pathlib sekitar dua kali lebih lambat untuk file dengan ekstensi .py , dan empat kali lebih lambat ketika diluncurkan di direktori home saya. Kesenjangan kinerja relatif antara pathlib dan os luas.


Dalam kasus saya, kecepatan ini tidak banyak berubah. Saya mencari semua file di direktori saya dan kehilangan 6 detik. Jika saya memiliki tugas memproses 10 juta file, kemungkinan besar saya akan menulis ulang. Tetapi sementara tidak ada kebutuhan seperti itu, Anda bisa menunggu.


Jika Anda memiliki sepotong kode yang panas dan pathlib jelas berdampak negatif terhadap operasinya, tidak ada yang salah dengan menggantinya dengan alternatif. Anda sebaiknya tidak mengoptimalkan kode, yang bukan merupakan hambatan - ini adalah pemborosan waktu, yang juga biasanya mengarah pada kode yang sulit dibaca, tanpa banyak buang.


Peningkatan keterbacaan


Saya ingin mengakhiri aliran pemikiran ini dengan beberapa contoh refactoring menggunakan pathlib . Saya mengambil beberapa contoh kecil kode yang berfungsi dengan file dan membuatnya bekerja dengan pathlib . Saya akan meninggalkan sebagian besar kode tanpa mengomentari pengadilan Anda - memutuskan versi mana yang paling Anda sukai.


Ini adalah fungsi make_editorconfig kita lihat sebelumnya:


 import os import os.path def make_editorconfig(dir_path): """Create .editorconfig file in given directory and return filename.""" filename = os.path.join(dir_path, '.editorconfig') if not os.path.exists(filename): os.makedirs(dir_path, exist_ok=True) open(filename, mode='wt').write('') return filename 

Dan ini adalah versi yang ditulis ulang di pathlib :


 from pathlib import Path def make_editorconfig(dir_path): """Create .editorconfig file in given directory and return filepath.""" path = Path(dir_path, '.editorconfig') if not path.exists(): path.parent.mkdir(exist_ok=True, parent=True) path.touch() return path 

Berikut adalah program konsol yang mengambil garis dengan direktori dan mencetak isi file .gitignore , jika ada:


 import os.path import sys directory = sys.argv[1] ignore_filename = os.path.join(directory, '.gitignore') if os.path.isfile(ignore_filename): with open(ignore_filename, mode='rt') as ignore_file: print(ignore_file.read(), end='') 

Hal yang sama dengan pathlib :


 from pathlib import Path import sys directory = Path(sys.argv[1]) ignore_path = directory / '.gitignore' if ignore_path.is_file(): print(ignore_path.read_text(), end='') 

Berikut adalah program yang mencetak semua file duplikat di folder dan subfolder saat ini:


 from collections import defaultdict from hashlib import md5 from os import getcwd, walk import os.path def find_files(filepath): for root, directories, filenames in walk(filepath): for filename in filenames: yield os.path.join(root, filename) file_hashes = defaultdict(list) for path in find_files(getcwd()): with open(path, mode='rb') as my_file: file_hash = md5(my_file.read()).hexdigest() file_hashes[file_hash].append(path) for paths in file_hashes.values(): if len(paths) > 1: print("Duplicate files found:") print(*paths, sep='\n') 

Hal yang sama dengan c pathlib :


 from collections import defaultdict from hashlib import md5 from pathlib import Path def find_files(filepath): for path in Path(filepath).rglob('*'): if path.is_file(): yield path file_hashes = defaultdict(list) for path in find_files(Path.cwd()): file_hash = md5(path.read_bytes()).hexdigest() file_hashes[file_hash].append(path) for paths in file_hashes.values(): if len(paths) > 1: print("Duplicate files found:") print(*paths, sep='\n') 

, , -, . pathlib .


pathlib.Path


.


/ pathlib.Path . , .


 >>> path1 = Path('dir', 'file') >>> path2 = Path('dir') / 'file' >>> path3 = Path('dir/file') >>> path3 WindowsPath('dir/file') >>> path1 == path2 == path3 True 

Python (. open ) Path , , pathlib , !


 from shutil import move def rename_and_redirect(old_filename, new_filename): move(old, new) with open(old, mode='wt') as f: f.write(f'This file has moved to {new}') 

 >>> from pathlib import Path >>> old, new = Path('old.txt'), Path('new.txt') >>> rename_and_redirect(old, new) >>> old.read_text() 'This file has moved to new.txt' 

pathlib , , PathLike . , , , PEP 519 .


 >>> from plumbum import Path >>> my_path = Path('old.txt') >>> with open(my_path) as f: ... print(f.read()) ... This file has moved to new.txt 

pathlib , ( , ), , .


, pathlib . Python :


 from pathlib import Path gitignore = Path('.gitignore') if gitignore.is_file(): print(gitignore.read_text(), end='') 

pathlib — . !

Source: https://habr.com/ru/post/id453862/


All Articles