من المترجم: مرحبا يا هبر! أقدم إليكم ترجمة المقال لماذا يجب أن تستخدم pathlib واستمراره ، لا حقًا ، Pathlib رائع . يتم الآن إيلاء الكثير من الاهتمام لميزات Python الجديدة مثل التزامن ، و: = العامل ، والكتابة الاختيارية. في الوقت نفسه ، ليست مهمة للغاية (على الرغم من :: استدعاء لغة ابتكار جادة لا تكون ابتكارًا جادًا) المخاطرة بالمرور وراء الرادار ، ولكن الابتكارات المفيدة جدًا في اللغة. على وجه الخصوص ، في مجموعة كبيرة من المقالات المخصصة لموضوع ما ، لم أجد (باستثناء فقرة واحدة هنا ) ، لذلك قررت أن أصحح الموقف.
عندما اكتشفت الوحدة النمطية pathlib الجديدة قبل بضع سنوات ، قررت من أسفل ذهني أنها كانت مجرد نسخة موجهة قليلاً للكائن من الوحدة النمطية os.path
. كنت مخطئا. pathlib
رائع حقا!
في هذه المقالة سأحاول الوقوع في حب pathlib
. آمل أن pathlib
هذه المقالة لاستخدام pathlib
في أي موقف يتعلق بالعمل مع الملفات في Python .
الجزء 1
os.path
حرج
os.path
وحدة os.path
هي ما استخدمناه عندما يتعلق الأمر بمسارات Python. من حيث المبدأ ، هناك كل ما تحتاجه ، ولكن في كثير من الأحيان لا تبدو أنيقة للغاية.
يجب أن استيراده من هذا القبيل؟
import os.path BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')
او هكذا؟
from os.path import abspath, dirname, join BASE_DIR = dirname(dirname(abspath(__file__))) TEMPLATES_DIR = join(BASE_DIR, 'templates')
ربما يكون لوظيفة الصلة اسمًا عامًا جدًا ، ويجب أن نفعل شيئًا مثل هذا:
from os.path import abspath, dirname, join as joinpath BASE_DIR = dirname(dirname(abspath(__file__))) TEMPLATES_DIR = joinpath(BASE_DIR, 'templates')
بالنسبة لي ، كل الخيارات المذكورة أعلاه لا تبدو مريحة للغاية. نقوم بتمرير السلاسل إلى الوظائف التي ترجع السلاسل التي ننقلها إلى الوظائف التالية التي تعمل مع السلاسل. لقد حدث أن تحتوي جميعها على مسارات ، لكنها لا تزال مجرد خطوط.
استخدام سلاسل الإدخال والإخراج في وظائف os.path
مريح للغاية لأن عليك قراءة الكود من الداخل إلى الخارج. أود تحويل هذه المكالمات من متداخلة إلى متسلسلة. هذا هو ما يسمح لك pathlib
!
from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent TEMPLATES_DIR = BASE_DIR.joinpath('templates')
تتطلب الوحدة النمطية os.path
استدعاءات الدوال المتداخلة ، لكن pathlib
يسمح لنا بإنشاء سلاسل من المكالمات المتتالية إلى أساليب وسمات فئة Path
بنتيجة مكافئة.
أعلم ما هو رأيك: توقف ، كائنات Path
هذه ليست هي نفسها كما كانت من قبل ، لم نعد نعمل على خطوط المسار! سوف نعود إلى هذه المشكلة لاحقًا (تلميح: في أي حالة تقريبًا ، تكون هاتان الطريقتان قابلة للتبادل).
os
مثقلة
تم os.path
الوحدة النمطية os.path
الكلاسيكية للعمل مع المسارات. ولكن بعد رغبتك في القيام بشيء ما باستخدام المسار (على سبيل المثال ، إنشاء دليل) ، ستحتاج إلى الوصول إلى وحدة نمطية أخرى ، غالبًا ما تكون os
.
يحتوي os
على مجموعة من الأدوات المساعدة للعمل مع الملفات والدلائل: mkdir
، getcwd
، chmod
، stat
، remove
، rename
، rmdir
. أيضا chdir
، link
، walk
، listdir
، makedirs
، renames
، removedirs
، unlink
symlink
، symlink
. ومجموعة كاملة من الأشياء التي لا تتعلق بأنظمة الملفات على الإطلاق: fork
، getenv
، putenv
، environ
، getlogin
، system
، ... بضع عشرات من الأشياء التي لن أذكرها هنا.
تم تصميم الوحدة os
لمجموعة واسعة من المهام. هذا هو مثل هذا المربع مع كل ما يتعلق بنظام التشغيل. هناك العديد من الفوائد في os
، ولكن ليس من السهل دائمًا التنقل: من الضروري غالبًا التنقل في الوحدة قبل العثور على ما تحتاج إليه.
pathlib
ينقل معظم وظائف نظام الملفات إلى كائنات Path
.
إليك الرمز الذي ينشئ دليل src/__pypackages__
ويعيد تسمية .editorconfig
إلى 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'))
هنا هو رمز مماثل باستخدام Path
from pathlib import Path Path('src/__pypackages__').mkdir(parents=True, exist_ok=True) Path('.editorconfig').rename('src/.editorconfig')
لاحظ أن نموذج التعليمات البرمجية الثاني أسهل في القراءة ، لأنه منظم من اليسار إلى اليمين - كل هذا بفضل سلاسل الطرق.
لا تنسى عن العالم
ليس فقط os
و os.path
يحتويان على طرق مرتبطة بنظام الملفات. كما تجدر الإشارة إلى حول العالم ، والتي لا يمكن أن يسمى عديمة الفائدة.
يمكننا استخدام وظيفة glob.glob
للبحث عن الملفات حسب نمط محدد:
from glob import glob top_level_csv_files = glob('*.csv') all_csv_files = glob('**/*.csv', recursive=True)
pathlib
الوحدة النمطية pathlib
أيضًا طرقًا مماثلة:
from pathlib import Path top_level_csv_files = Path.cwd().glob('*.csv') all_csv_files = Path.cwd().rglob('*.csv')
بعد التبديل إلى الوحدة النمطية pathlib
، تختفي بالكامل الحاجة إلى الوحدة النمطية pathlib
: كل ما تحتاجه بالفعل جزء لا يتجزأ من كائنات Path
pathlib
يجعل الأشياء البسيطة أسهل
pathlib
تبسيط العديد من المواقف الصعبة ، ولكنه يجعل بعض pathlib
التعليمات البرمجية البسيطة أسهل .
هل تريد قراءة كل النص في ملف واحد أو أكثر؟
يمكنك فتح الملف ، وقراءة المحتويات ، وإغلاق الملف باستخدام الكتلة 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())
أو يمكنك استخدام طريقة read_text
على كائنات Path
وإنشاء قوائم للحصول على نفس النتيجة في تعبير واحد:
from pathlib import Path file_contents = [ path.read_text() for path in Path.cwd().rglob('*.py') ]
ولكن ماذا لو كنت بحاجة إلى الكتابة إلى ملف؟
إليك ما يشبه استخدام open
:
with open('.editorconfig') as config: config.write('# config goes here')
أو يمكنك استخدام الأسلوب write_text
:
Path('.editorconfig').write_text('# config goes here')
إذا كنت بحاجة إلى استخدام open
، لسبب ما ، إما كمدير للسياق أو للتفضيلات الشخصية ، يوفر Path
الطريقة open
كبديل:
from pathlib import Path path = Path('.editorconfig') with path.open(mode='wt') as config: config.write('# config goes here')
أو بدءًا من Python 3.6 ، يمكنك تمرير Path
مباشرة open
:
from pathlib import Path path = Path('.editorconfig') with open(path, mode='wt') as config: config.write('# config goes here')
كائنات المسار تجعل الشفرة أكثر وضوحًا
ماذا تشير المتغيرات التالية؟ ما معنى معانيها؟
person = '{"name": "Trey Hunner", "location": "San Diego"}' pycon_2019 = "2019-05-01" home_directory = '/home/trey'
كل متغير يشير إلى خط. لكن لكل منهما معاني مختلفة: الأول هو JSON ، والثاني هو التاريخ ، والثالث هو مسار الملف.
هذا التمثيل للكائنات مفيد أكثر قليلاً:
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')
يمكن إلغاء تسلسل كائنات JSON إلى قاموس ، ويمكن تمثيل التواريخ أصليًا باستخدام datetime.date
، ويمكن تمثيل كائنات مسار الملف Path
باستخدام كائنات Path
يجعل التعليمات البرمجية الخاصة بك أكثر وضوحًا. إذا كنت ترغب في العمل مع التواريخ ، فإنك تستخدم date
. إذا كنت تريد العمل مع مسارات الملفات ، فاستخدم Path
.
أنا لست مؤيدًا كبيرًا جدًا لـ OOP. تضيف الطبقات طبقة إضافية من التجريد ، وتميل التجريدات في بعض الأحيان إلى تعقيد النظام بدلاً من تبسيطه. في الوقت نفسه ، أعتقد أن pathlib.Path
عبارة عن تجريد مفيد . بسرعة كبيرة ، يصبح قرارا مقبولا.
بفضل PEP 519 ، أصبحت Path
قياسية للعمل مع المسارات. في وقت Python 3.6 ، تعمل معظم أساليب os
، shutil
، os.path
بشكل صحيح مع هذه الكائنات. يمكنك التبديل إلى pathlib
، شفافة لقاعدة التعليمات البرمجية الخاصة بك!
ما هو مفقود في pathlib
؟
على الرغم من أن pathlib
رائع ، إلا أنه ليس شاملاً. هناك بالتأكيد العديد من الاحتمالات التي أود تضمينها في الوحدة .
أول ما يتبادر إلى الذهن هو عدم وجود طرق تعادل مسار shutil
. على الرغم من أنه يمكنك تمرير Path
كمعلمات shutil
للنسخ / حذف / نقل الملفات والدلائل ، لا يمكنك shutil
على كائنات Path
.
لذلك ، لنسخ الملفات ، تحتاج إلى القيام بشيء مثل هذا:
from pathlib import Path from shutil import copyfile source = Path('old_file.txt') destination = Path('new_file.txt') copyfile(source, destination)
لا يوجد أيضًا أي os.chdir
لطريقة os.chdir
. هذا يعني أنك بحاجة إلى استيراده إذا كنت بحاجة إلى تغيير الدليل الحالي:
from pathlib import Path from os import chdir parent = Path('..') chdir(parent)
لا يوجد أيضًا ما يعادل وظيفة os.walk
. على الرغم من أنه يمكنك كتابة وظيفتك بروح walk
دون الكثير من الصعوبة.
آمل أن pathlib.Path
كائنات pathlib.Path
يوم على أساليب لبعض العمليات المذكورة. لكن حتى في هذا السيناريو ، أجد أنه من الأسهل بكثير استخدام pathlib
مع شيء آخر غير استخدام os.path
وكل شيء آخر .
هل من الضروري دائمًا استخدام pathlib
؟
بدءًا من Python 3.6 ، تعمل المسارات في كل مكان تقريبًا تستخدم فيه السلاسل . لذلك لا أرى أي سبب لعدم استخدام pathlib
إذا كنت تستخدم Python 3.6 وما فوق.
إذا كنت تستخدم إصدارًا سابقًا من Python 3 ، فيمكنك في أي وقت التفاف كائن Path
في استدعاء str
للحصول على سلسلة إذا كنت بحاجة إلى العودة إلى بلد الخطوط. هذا ليس أنيقًا جدًا ، لكنه يعمل:
from os import chdir from pathlib import Path chdir(Path('/home/trey'))
الجزء 2. إجابات على الأسئلة.
بعد نشر الجزء الأول ، كان لدى بعض الأشخاص بعض الأسئلة. قال أحدهم أنني قارنت pathlib
و pathlib
. قال البعض إن استخدام os.path
متأصل جدًا في مجتمع Python بحيث يستغرق الانتقال إلى مكتبة جديدة وقتًا طويلاً للغاية. رأيت أيضًا بعض الأسئلة حول الأداء.
في هذا الجزء ، أود التعليق على هذه القضايا. يمكن اعتبار pathlib
حماية لكل من pathlib
وقليلًا من رسالة حب إلى PEP 519 .
قارن os.path
و pathlib
أن نكون صادقين
في الجزء الأخير ، قارنت شظايا الكود التاليين:
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')
قد يبدو هذا بمثابة مقارنة غير عادلة ، لأن استخدام os.path.join
في المثال الأول يضمن استخدام المحددات الصحيحة على جميع الأنظمة الأساسية ، وهو ما لم أفعله في المثال الثاني. في الواقع ، كل شيء في محله ، لأن Path يقوم تلقائيًا بتنظيم فواصل المسار
يمكننا إثبات ذلك من خلال النظر في تحويل كائن Path
إلى سلسلة على Windows:
>>> str(Path('src/__pypackages__')) 'src\\__pypackages__'
لا فرق ما إذا كنا نستخدم طريقة joinpath
، أو '/'
في سطر المسار ، و /
المشغل (ميزة لطيفة أخرى من Path
) ، أو نقل وسيطات فردية إلى مُنشئ Path ، نحصل على نفس النتيجة:
>>> 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')
تسبب المثال الأخير في حدوث بعض الالتباس من الأشخاص الذين اقترحوا أن pathlib
يكن ذكيًا بدرجة كافية لاستبدال /
ب \
في سلسلة المسار. لحسن الحظ ، كل شيء في محله!
مع كائنات Path
، لم تعد بحاجة للقلق بشأن اتجاه الخطوط المائلة: حدد جميع مساراتك باستخدام /
، وستكون النتيجة متوقعة لأي نظام أساسي.
لا داعي للقلق بشأن تطبيع المسارات.
إذا كنت تقوم بتشغيل Linux أو Mac ، فمن السهل جدًا إضافة الأخطاء إلى التعليمات البرمجية التي تؤثر على مستخدمي Windows فقط. إذا لم تراقب بعناية استخدام os.path.join
و \ أو os.path.normcase
لتحويل os.path.normcase
المائلة إلى تلك المناسبة للنظام الأساسي الحالي ، فيمكنك كتابة التعليمات البرمجية التي لن تعمل بشكل صحيح على Windows .
فيما يلي مثال على خطأ خاص بـ 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')
علاوة على ذلك ، سيعمل هذا الرمز بشكل صحيح في كل مكان:
import sys from pathlib import Path directory = '.' if not sys.argv[1:] else sys.argv[1] new_file = Path(directory, 'new_package/__init__.py')
في السابق ، كان المبرمج مسؤولاً عن مسارات التسلسل وتطبيعها ، مثلما حدث في بيثون 2 ، كان المبرمج مسؤولاً عن تحديد مكان استخدام يونيكود بدلاً من البايتات. هذه ليست مهمتك بعد الآن - Path
يحل كل هذه المشاكل لك.
لا أستخدم Windows ، وليس لدي كمبيوتر يعمل بنظام Windows. لكن من المحتمل أن يستخدم الكثير من الأشخاص الذين يستخدمون الكود الخاص بي Windows ، وأريد أن يعمل كل شيء بشكل صحيح لهم.
إذا كانت هناك فرصة لتشغيل التعليمات البرمجية الخاصة بك على Windows ، فيجب عليك التفكير بجدية في التبديل إلى pathlib
.
لا تقلق بشأن التطبيع : استخدم Path
أي حال عندما يتعلق الأمر بمسارات المسارات.
pathlib
رائعة ، لكن لدي مكتبة تابعة لجهة خارجية لا تستخدم pathlib
!
لديك قاعدة رمز كبيرة تعمل مع سلاسل كمسارات. لماذا التبديل إلى pathlib
إذا كان هذا يعني أن كل شيء يحتاج إلى إعادة كتابة؟
دعنا نتخيل أن لديك الوظيفة التالية:
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
تأخذ الوظيفة دليلًا وتقوم بإنشاء ملف .editorconfig
، شيء من هذا القبيل:
>>> import os.path >>> make_editorconfig(os.path.join('src', 'my_package')) 'src/my_package/.editorconfig'
إذا قمت باستبدال الخطوط بـ Path
، Path
كل شيء أيضًا:
>>> from pathlib import Path >>> make_editorconfig(Path('src/my_package')) 'src/my_package/.editorconfig'
لكن ... كيف؟
يقبل os.path.join
كائنات Path
(منذ Python 3.6). ويمكن قول الشيء نفسه من os.makedirs
.
في الواقع ، تقبل الدالة open
المضمنة Path
، وتقبل shutil
Path
وكل شيء في المكتبة القياسية المستخدمة لقبول السلاسل يجب أن يعمل الآن مع كل من Path
والخيوط.
يجب أن نشكر PEP 519 على هذا ، الذي وفر os.PathLike
للفئة المجردة وأعلن أن جميع الأدوات المساعدة المضمنة للعمل مع مسارات الملفات يجب أن تعمل الآن مع كل من السلاسل Path
.
لكن مكتبتي المفضلة بها Path ، أفضل من المعيار!
قد تكون بالفعل تستخدم مكتبة تابعة لجهة خارجية توفر تطبيق Path
الخاص بها ، وهو يختلف عن المكتبة القياسية. ربما تحبها أكثر.
على سبيل المثال ، يحتوي كل من django-environ و path.py و plumbum و visidata على كائنات Path
الخاصة بهم. بعض هذه المكتبات أقدم من pathlib
، وقررت أن ترث من str
بحيث يمكن نقلها إلى وظائف تتوقع سلاسل كمسارات. بفضل PEP 519 ، سيكون دمج مكتبات الجهات الخارجية في الكود أسهل ، ودون الحاجة إلى الميراث من str
.
دعونا نتخيل أنك لا تريد استخدام pathlib
، لأن Path
كائنات ثابتة ، وتريد حقًا تغيير حالتها. مع PEP 519 ، يمكنك إنشاء أفضل نسخة قابلة للتغيير من Path
. للقيام بذلك ، فقط قم بتنفيذ الأسلوب __fspath__
يمكن الآن لأي تطبيق مكتوب ذاتي لـ Path
أن يعمل أصلاً مع وظائف Python المدمجة التي تتوقع مسارات الملفات. حتى إذا كنت لا تحب pathlib
، فإن حقيقة وجودها تعد إضافة كبيرة لمكتبات الجهات الخارجية ذات Path
الخاص بها
لكن pathlib.Path
و str
لا يختلطان ، أليس كذلك؟
ربما تظن: هذا كل شيء رائع بالطبع ، لكن هل ستضيف هذه الطريقة مع المسار أحيانًا وأحيانًا بعض التعقيد إلى الكود الخاص بي؟
الجواب على هذا السؤال هو نعم ، إلى حد ما. ولكن هذه المشكلة لها حل بسيط للغاية.
أضافت PEP 519 بضعة أشياء أخرى إلى جانب PathLike
: أولاً ، إنها طريقة لتحويل أي PathLike
إلى سلسلة ، وثانياً ، إنها وسيلة لتحويل أي PathLike
إلى Path
.
لنأخذ كائنين - السلسلة Path
(أو أي شيء باستخدام طريقة fspath ):
from pathlib import Path import os.path p1 = os.path.join('src', 'my_package') p2 = Path('src/my_package')
تعمل دالة os.fspath
تطبيع كل من الكائنات وتحويلها إلى سلاسل:
>>> from os import fspath >>> fspath(p1), fspath(p2) ('src/my_package', 'src/my_package')
في هذه الحالة ، يمكن أن يأخذ Path
كلا هذين الكائنين في مُنشئ وتحويلهما إلى Path
:
>>> Path(p1), Path(p2) (PosixPath('src/my_package'), PosixPath('src/my_package'))
هذا يعني أنه يمكنك تحويل نتيجة make_editorconfig
مرة أخرى إلى Path
إذا لزم الأمر:
>>> from pathlib import Path >>> Path(make_editorconfig(Path('src/my_package'))) PosixPath('src/my_package/.editorconfig')
على الرغم من أن أفضل حل بالطبع هو إعادة كتابة make_editorconfig
باستخدام pathlib
.
pathlib
بطيء جدا
لقد رأيت عدة مرات عن أداء pathlib
. هذا صحيح - pathlib
يمكن أن يكون بطيئا. يمكن أن يؤثر إنشاء الآلاف من كائنات Path
بشكل كبير على سلوك البرنامج.
قررت قياس أداء pathlib
و os.path
على جهاز الكمبيوتر الخاص بي باستخدام برنامجين مختلفين os.path
عن جميع ملفات .py
في الدليل الحالي
هنا هو إصدار 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")
وهنا هو الإصدار مع 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")
يعد اختبار أداء البرامج التي تعمل مع نظام الملفات مهمة صعبة ، لأن وقت التشغيل يمكن أن يتغير كثيرًا. قررت تشغيل كل برنامج نصي 10 مرات ومقارنة أفضل النتائج لكل برنامج.
عثر كلا البرنامجين على 97507 ملفًا في الدليل الذي قمت بتشغيله عليهما. عملت الأولى في 1.914 ثانية ، والثانية في 3.430 ثانية.
عندما أقوم بتعيين المعلمة extension=''
، تعثر هذه البرامج على حوالي 600000 ملف ، ويزيد الفارق. عمل البرنامج الأول في 1.888 ثانية ، والثاني في 7.485 ثانية.
لذلك ، فإن pathlib
يكون بطيئًا في الملفات ذات الامتداد .py
، وأبطأ أربع مرات عند تشغيله في الدليل الرئيسي. فجوة الأداء النسبية بين pathlib
و os
واسعة.
في حالتي ، هذه السرعة لا تتغير كثيرا. لقد فتشت كل الملفات في الدليل وفقدت 6 ثوان. إذا كانت لدي مهمة معالجة 10 ملايين ملف ، فمن المرجح أن أعد كتابتها. لكن على الرغم من عدم وجود مثل هذه الحاجة ، يمكنك الانتظار.
إذا كانت لديك شفرة pathlib
وتؤثر pathlib
بشكل واضح سلبًا على عملها ، فلا حرج في استبدالها ببديل. لا ينبغي عليك تحسين الكود ، وهو ليس عنق الزجاجة - إنه مضيعة للوقت الإضافي ، والذي يؤدي عادةً إلى شفرة سيئة القراءة ، دون الكثير من العادم.
تحسين قابلية القراءة
أرغب في إنهاء مجموعة الأفكار هذه ببعض الأمثلة عن إعادة pathlib
باستخدام pathlib
. أخذت بضعة أمثلة صغيرة من التعليمات البرمجية التي تعمل مع الملفات وجعلتها تعمل مع pathlib
. سأترك معظم الشفرة دون تعليق على ملعبك - حدد الإصدار الذي تفضله أكثر.
فيما يلي وظيفة make_editorconfig
التي رأيناها سابقًا:
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
pathlib
النسخة المعاد كتابتها في 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
فيما يلي برنامج وحدة تحكم يأخذ خطًا بدليل ويطبع محتويات ملف .gitignore
، إذا كان موجودًا:
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='')
نفس الشيء مع 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='')
فيما يلي برنامج يقوم بطباعة جميع الملفات المكررة في المجلد الحالي والمجلدات الفرعية:
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')
نفس الشيء مع 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
— . !