عند تطوير برنامج نصي مستقل بلغة بايثون، قد لا تلاحظ أي شيء غير عادي في بنية الدليل لديك. ومع ذلك، بمجرد أن يصبح مشروعك أكثر تعقيدًا، ستقرر غالبًا استخراج أجزاء من الدالة في وحدات أو حزم إضافية. في هذه الحالة، قد تبدأ في رؤية مجلد __pycache__
يظهر من العدم بجوار ملفات المصدر في أماكن عشوائية على ما يبدو:
project/
│
├── mathematics/
│ │
│ ├── __pycache__/
│ │
│ ├── arithmetic/
│ │ ├── __init__.py
│ │ ├── add.py
│ │ └── sub.py
│ │
│ ├── geometry/
│ │ │
│ │ ├── __pycache__/
│ │ │
│ │ ├── __init__.py
│ │ └── shapes.py
│ │
│ └── __init__.py
│
└── calculator.py
لاحظ أن مجلد __pycache__
قد يكون موجودًا على مستويات مختلفة في شجرة دليل مشروعك عندما يكون لديك حزم فرعية متعددة متداخلة مع بعضها البعض. في الوقت نفسه، قد لا تحتوي الحزم أو المجلدات الأخرى التي تحتوي على ملفات مصدر بايثون على دليل ذاكرة التخزين المؤقت الغامض هذا.
ملاحظة: للحفاظ على مساحة عمل أكثر نظافة، يتم إعداد العديد من بيئات التطوير المتكاملة ومحرري التعليمات البرمجية الخاصة بـ بايثون بشكل جاهز لإخفاء مجلدات __pycache__ عنك، حتى إذا كانت هذه المجلدات موجودة على نظام الملفات الخاص بك.
قد تواجه موقفًا مشابهًا بعد استنساخ مستودع Git بعيد باستخدام مشروع بايثون وتشغيل الكود الأساسي. إذن، ما الذي يسبب ظهور مجلد __pycache__
، ولأي غرض؟
باختصار: يجعل استيراد وحدات بايثون أسرع
على الرغم من أن بايثون هي لغة برمجة مفسرة، فإن مفسّرها لا يعمل مباشرة على كود بايثون الخاص بك، مما قد يؤدي إلى بطء شديد. بدلاً من ذلك، عند تشغيل برنامج نصي بايثون أو استيراد وحدة بايثون، يقوم المفسّر بتجميع كود المصدر بايثون عالي المستوى إلى بايت كود، وهو تمثيل ثنائي وسيط للكود.
يتيح هذا بايت كود للمترجم تخطي الخطوات المتكررة، مثل تحليل الكود وتحليله إلى شجرة بناء جملة مجردة والتحقق من صحته في كل مرة تقوم فيها بتشغيل نفس البرنامج. طالما لم يتغير الكود المصدر الأساسي، يمكن لـبايثون إعادة استخدام التمثيل الوسيط، والذي يكون جاهزًا للتنفيذ على الفور. هذا يوفر الوقت، ويسرع وقت بدء تشغيل البرنامج النصي الخاص بك.
تذكر أنه على الرغم من أن تحميل البايت كود المجمّع من __pycache__ يجعل استيراد وحدات بايثون أسرع، إلا أنه لا يؤثر على سرعة تنفيذها!
يستخدم بايثون مجلدات __pycache__ المحلية لتخزين البايت كود المجمّع للوحدات النمطية المستوردة في مشروعك. في عمليات التشغيل اللاحقة، سيحاول المترجم تحميل إصدارات مجمعة مسبقًا من الوحدات النمطية من هذه المجلدات، بشرط أن تكون محدثة بملفات المصدر المقابلة. لاحظ أن آلية التخزين المؤقت هذه يتم تشغيلها فقط للوحدات النمطية التي تستوردها في الكود الخاص بك بدلاً من تنفيذها كنصوص برمجية في الطرفية.
بالإضافة إلى تخزين البايت كود على القرص، يحتفظ بايثون بذاكرة تخزين مؤقتة للوحدات، والتي يمكنك الوصول إليها من خلال قاموس sys.modules. وهذا يضمن أنه عند استيراد نفس الوحدة النمطية عدة مرات من أماكن مختلفة داخل برنامجك، سيستخدم بايثون الوحدة النمطية المستوردة بالفعل دون الحاجة إلى إعادة تحميلها أو إعادة تجميعها. تعمل الآليتان معًا لتقليل التكلفة الإضافية لاستيراد وحدات بايثون.
سوف تكتشف بالضبط مدى سرعة تحميل بايثون للبايت كود المخزن مؤقتًا مقارنة بتجميع الكود المصدر أثناء استيراد وحدة.
ما مدى سرعة تحميل الوحدات من ذاكرة التخزين المؤقت؟
تتم عملية التخزين المؤقت خلف الكواليس وعادةً ما تمر دون أن يلاحظها أحد نظرًا لأن بايثون سريع جدًا في تجميع الكود الثنائي. بالإضافة إلى ذلك، ما لم تقم غالبًا بتشغيل نصوص بايثون قصيرة العمر، تظل خطوة التجميع غير مهمة عند مقارنتها بإجمالي وقت التنفيذ. ومع ذلك، بدون التخزين المؤقت، يمكن أن تتراكم النفقات العامة المرتبطة بتجميع الكود الثنائي إذا كان لديك الكثير من الوحدات وقمت باستيرادها عدة مرات.
لقياس الفرق في وقت الاستيراد بين وحدة مخزنة مؤقتًا ووحدة غير مخزنة مؤقتًا، يمكنك تمرير خيار -X importtime إلى أمر بايثون أو تعيين متغير البيئة المكافئ PYTHONPROFILEIMPORTTIMEح. عند تمكين هذا الخيار، سيعرض بايثون جدولًا يلخص المدة التي استغرقها استيراد كل وحدة، بما في ذلك الوقت التراكمي في حالة اعتماد وحدة على وحدات أخرى.
افترض أن لديك برنامجًا نصيًا calculator.py يستورد ويستدعي دالة مساعدة من وحدة arithmetic.py المحلية:
from arithmetic import add
add(3, 4)
تعرف الوحدة المستوردةدالة واحدة:
def add(a, b):
return a + b
كما ترى، يقوم البرنامج النصي الرئيسي بتفويض إضافة رقمين، ثلاثة وأربعة، إلى دالة add()
المستوردة من وحدة arithmetic.
ملاحظة: على الرغم من أنك تستخدم صيغة
from ... import
والتي تجلب الرمز المحدد فقط إلى مساحة الأسماء الحالية، فإن بايثون يقرأ الوحدة بالكامل ويجمعها على أي حال. علاوة على ذلك، فإن عمليات الاستيراد غير المستخدمة ستؤدي أيضًا إلى تشغيل التجميع.
في المرة الأولى التي تقوم فيها بتشغيل البرنامج النصي، يقوم بايثون بتجميع وحفظ الكود الثنائي للوحدة التي قمت باستيرادها في مجلد __pycache__ محلي. إذا لم يكن هذا المجلد موجودًا بالفعل، فسيقوم بايثون تلقائيًا بإنشاء مجلد قبل الانتقال. الآن، عند تنفيذ البرنامج النصي مرة أخرى، يجب أن يجد بايثون الكود الثنائي المخزن مؤقتًا ويقوم بتحميله طالما لم تقم بتغيير الكود المصدر المرتبط.
بمجرد تسخين ذاكرة التخزين المؤقت، فسوف يساهم ذلك في تسريع وقت بدء تشغيل البرنامج النصي بايثون:
$ python -X importtime calculator.py
(...)
import time: 20092 | 20092 | arithmetic
$ python -X importtime calculator.py
(...)
import time: 232 | 232 | arithmetic
$ python -X importtime calculator.py
(...)
import time: 203 | 203 | arithmetic
على الرغم من أن القياسات الدقيقة قد تختلف عبر عمليات التشغيل، فإن التحسن واضح للعيان. فبدون مجلد __pycache__، كانت المحاولة الأولية لاستيراد العمليات الحسابية أبطأ بمقدار مرتبتين من حيث الحجم مقارنة بعمليات التشغيل اللاحقة. قد يبدو هذا التغيير مذهلاً للوهلة الأولى، ولكن يتم التعبير عن هذه القيم بالمايكروثانية، لذا فمن المرجح أنك لن تلاحظ الفرق على الرغم من هذا الانخفاض الكبير في الأرقام.
عادةً ما ينعكس اكتساب الأداء بالكاد في وقت بدء تشغيل معظم نصوص بايثون، والذي يمكنك تقييمه باستخدام الأمر time على أنظمة شبيهة بنظام Unix:
$ rm -rf __pycache__
$ time python calculator.py
real 0m0.088s
user 0m0.064s
sys 0m0.028s
$ time python calculator.py
real 0m0.086s
user 0m0.060s
sys 0m0.030s
هنا، يظل إجمالي وقت التنفيذ كما هو تقريبًا بغض النظر عن وجود ذاكرة التخزين المؤقت أم لا. يؤدي إزالة مجلد __pycache__ إلى تأخير التنفيذ بحوالي ملي ثانية، وهو أمر لا يُذكَر بالنسبة لمعظم التطبيقات.
الآن بعد أن تعرفت على غرض مجلد __pycache__، قد تشعر بالفضول تجاه محتواه.
ماذا يوجد داخل مجلد __pycache__
؟
عند إلقاء نظرة داخل مجلد __pycache__، سترى ملفًا واحدًا أو أكثر ينتهي بامتداد .pyc. وهو يرمز إلى وحدة بايثون المجمعة:
$ ls -1 __pycache__
arithmetic.cpython-311.pyc
arithmetic.cpython-312.pyc
arithmetic.pypy310.opt-1.pyc
arithmetic.pypy310.opt-2.pyc
arithmetic.pypy310.pyc
solver.cpython-312.pyc
units.cpython-312.pyc
يحتوي كل ملف من هذه الملفات على الكود الثنائي لوحدة بايثون المقابلة، المحددة في الحزمة الحالية، والتي قمت باستيرادها وقت التشغيل. يستهدف الكود الثنائي المجمّع تنفيذًا معينًا لـبايثون وإصدارًا ومستوى تحسين اختياريًا. يتم ترميز كل هذه المعلومات في اسم الملف.
على سبيل المثال، الملف المسمى arithmetic.pypy310.opt-2.pyc هو الكود الثنائي لوحدة arithmetic.py التي تم تجميعها بواسطة PyPy 3.10 بمستوى تحسين 2. يزيل هذا التحسين عبارات assert
ويتجاهل أي سلاسل توثيق. وعلى العكس من ذلك، يمثل arithmetic.cpython-312.pyc نفس الوحدة ولكن تم تجميعها لـ CPython 3.12 دون أي تحسينات.
في المجمل، هناك خمسة متغيرات للبايت كود تم تجميعها من وحدة arithmetic.py واحدة في المجلد __pycache__ أعلاه، والتي تم تسليط الضوء عليها.
يضمن مخطط تسمية الملفات هذا التوافق بين إصدارات ونكهات بايثون المختلفة. عند تشغيل نفس البرنامج النصي باستخدام PyPy أو إصدار CPython سابق، سيقوم المترجم بتجميع جميع الوحدات المستوردة مقابل بيئة التشغيل الخاصة به حتى يتمكن من إعادة استخدامها لاحقًا. يتم أيضًا تخزين إصدار بايثون، جنبًا إلى جنب مع البيانات الوصفية الأخرى، في ملف .pyc نفسه.
ستلقي نظرة فاحصة على ملفات .pyc المخزنة في مجلد ذاكرة التخزين المؤقت في نهاية هذا البرنامج التعليمي. الآن، حان الوقت للتعرف على الظروف التي تدفع بايثون إلى إنشاء مجلد ذاكرة التخزين المؤقت.
متى تقوم بايثون بإنشاء مجلدات ذاكرة التخزين المؤقت؟
سيقوم المترجم بتخزين البايت كود المجمّع لوحدات بايثون فقط في مجلد __pycache__ عندما تقوم باستيراد تلك الوحدات أو أحيانًا الحزمة الأصلية الخاصة بها. ولن يقوم بإنشاء مجلد ذاكرة التخزين المؤقت عندما تقوم بتشغيل نص برمجي عادي لبايثون لا يستورد أي وحدات أو حزم. ويستند هذا إلى افتراض أن الوحدات أقل عرضة للتغيير وأنك قد تقوم باستيرادها عدة مرات أثناء تنفيذ واحد.
ملاحظة: على الرغم من أنك لا تتعرض إلا لتجميع الكود الثنائي من خلال مجلد __pycache__ عندما تقوم باستيراد وحدات أو حزم محلية، فإن الآلية الأساسية تعمل بشكل جيد بنفس القدر بالنسبة للحزم التابعة لجهات خارجية وحزم المكتبات القياسية.
عند تثبيت حزمة خارجية في بيئة افتراضية، سيقوم pip افتراضيًا بتجميع وحدات الحزمة مسبقًا في ملفات .pyc باستخدام مفسّر بايثون الذي تعمل عليه حاليًا. وبالمثل، تأتي وحدات بايثون الخالصة في مكتبة بايثون القياسية مجمعة مسبقًا مع جميع مستويات التحسين الممكنة.
إذا قمت بإزالة أحد ملفات
.pyc
هذه، إما من مجلدsite-packages/
الخاص بالبيئة الافتراضية أو مجلدlib/
الخاص بـبايثون، فسوف يقوم المترجم بإعادة إنشائه في المرة التالية التي تقوم فيها باستيراد الوحدة النمطية المقابلة.
عند استيراد وحدة فردية من حزمة، سينتج بايثون ملف .pyc
المقابل ويخزنه مؤقتًا في مجلد __pycache__ الموجود داخل تلك الحزمة. كما سيعمل على تجميع ملف __init__.py الخاص بالحزمة ولكنه لن يمس أي وحدات أخرى أو حزم فرعية متداخلة. ومع ذلك، إذا كانت الوحدة المستوردة نفسها تستورد وحدات أخرى، فسيتم تجميع تلك الوحدات أيضًا، وهكذا.
فيما يلي مثال يوضح الحالة الأكثر أساسية، على افتراض أنك وضعت عبارة استيراد مناسبة في البرنامج النصي calculator.py أدناه:
project/
│
├── arithmetic/
│ │
│ ├── __pycache__/
│ │ ├── __init__.cpython-312.pyc
│ │ └── add.cpython-312.pyc
│ │
│ ├── __init__.py
│ ├── add.py
│ └── sub.py
│
└── calculator.py
بعد تشغيل البرنامج النصي لأول مرة، سيتأكد بايثون من وجود مجلد __pycache__
في حزمة arithmetic. ثم سيقوم بتجميع ملف __init__.py الخاص بالحزمة مع أي وحدات مستوردة من تلك الحزمة. في هذه الحالة، طلبت فقط استيراد وحدة arithmetic.add، لذا يمكنك رؤية ملف .pyc مرتبط بـ add.py ولكن ليس بـ sub.py.
ستؤدي جميع عبارات الاستيراد التالية إلى نفس النتيجة الموضحة أعلاه:
import arithmetic.add
from arithmetic import add
from arithmetic.add import add_function
بغض النظر عن كيفية استيراد وحدة بايثون وسواء كنت تستوردها بالكامل أو مجرد رمز محدد، مثل فئة، يقوم المترجم بتجميع الوحدة بأكملها، لأنه لا يمكنه قراءة الوحدات جزئيًا.
على العكس من ذلك، يؤدي استيراد حزمة كاملة عادةً إلى جعل بايثون يقوم بتجميع __init__.py فقط في تلك الحزمة. ومع ذلك، من الشائع إلى حد ما أن تعرض الحزم وحداتها الداخلية أو حزمها الفرعية من داخل __init__.py لسهولة الوصول إليها. على سبيل المثال، ضع في اعتبارك ما يلي:
from arithmetic import add
from arithmetic.sub import sub_function
إن عمليات الاستيراد داخل __init__.py مثل هذه تؤدي إلى إنشاء ملفات .pyc
إضافية، حتى عندما تستخدم عبارة import arithmetic
البسيطة في البرنامج النصي الخاص بك.
إذا قمت باستيراد حزمة فرعية أو وحدة أو رمز متداخلين بعمق، فسيتم أيضًا تجميع ملفات __init__.py الخاصة بكل الحزم الوسيطة المؤدية إلى الحزمة ذات المستوى الأعلى ووضعها في مجلدات التخزين المؤقت الخاصة بها. ومع ذلك، لن يسلك بايثون الاتجاه الآخر من خلال المسح المتكرر للحزم الفرعية المتداخلة، حيث لن يكون ذلك ضروريًا. سيقوم فقط بتجميع الوحدات التي تحتاجها حقًا عن طريق استيرادها صراحةً أو بشكل غير مباشر.
ماذا لو قام بايثون بالفعل بتجميع الوحدة في ملف .pyc
، ولكنك قررت تعديل الكود المصدر الخاص بها في ملف .py
الأصلي؟ ستكتشف ذلك لاحقًا!
ما هي الإجراءات التي تبطل ذاكرة التخزين المؤقت؟
قد يؤدي تشغيل رمز بايت قديم إلى حدوث خطأ أو، الأسوأ من ذلك، قد يؤدي إلى سلوك غير متوقع تمامًا. لحسن الحظ، يتمتع بايثون بالذكاء الكافي لاكتشاف وقت تعديلك للكود المصدر لوحدة مجمعة وإعادة تجميعه حسب الضرورة.
لتحديد ما إذا كانت الوحدة تحتاج إلى إعادة التجميع، يستخدم بايثون إحدى استراتيجيتي إبطال ذاكرة التخزين المؤقت:
- يعتمد على الطابع الزمني
- يعتمد على التجزئة
الطريقة الأولى تقارن حجم ملف المصدر وعلامة الوقت التي تم تعديله فيها مؤخرًا بالبيانات الوصفية المخزنة في ملف .pyc المقابل. ستتعلم لاحقًا كيف يتم الاحتفاظ بهذه القيم في ملف .pyc، إلى جانب البيانات الوصفية الأخرى.
على النقيض من ذلك، تحسب الإستراتيجية الثانية قيمة التجزئة لملف المصدر وتتحقق منها مقابل حقل خاص في رأس الملف (PEP 552)، والذي تم تقديمه في بايثون 3.7. هذه الإستراتيجية أكثر أمانًا وحتمية ولكنها أيضًا أبطأ قليلاً. ولهذا السبب تظل الإستراتيجية القائمة على الطابع الزمني هي الافتراضية في الوقت الحالي.
عندما تقوم بتحديث وقت التعديل (mtime) لملف المصدر بشكل مصطنع، على سبيل المثال، باستخدام الأمر touch على macOS أو Linux، فسوف تجبر بايثون على تجميع الوحدة مرة أخرى:
$ tree -D --dirsfirst
[Apr 26 09:48] .
├── [Apr 26 09:48] __pycache__
│ └── [Apr 26 09:48] arithmetic.cpython-312.pyc
├── [Apr 26 09:48] arithmetic.py
└── [Apr 26 09:48] calculator.py
2 directories, 3 files
$ touch arithmetic.py
$ python calculator.py
$ tree -D --dirsfirst
[Apr 26 09:48] .
├── [Apr 26 09:52] __pycache__
│ └── [Apr 26 09:52] arithmetic.cpython-312.pyc
├── [Apr 26 09:52] arithmetic.py
└── [Apr 26 09:48] calculator.py
2 directories, 3 files
في البداية، تم تعديل ملف arithmetic.cpython-312.pyc المخزن مؤقتًا آخر مرة في الساعة 09:48 صباحًا. بعد لمس ملف المصدر، arithmetic.py، يعتبر بايثون أن البايت كود المجمّع قديم ويعيد تجميع الوحدة النمطية عند تشغيل البرنامج النصي الذي يستورد arithmetic. يؤدي هذا إلى إنشاء ملف .pyc جديد بعلامة زمنية محدثة في الساعة 09:52 صباحًا.
لإنتاج ملفات .pyc تعتمد على التجزئة، يجب عليك استخدام وحدة compileall في بايثون مع تعيين خيار –invalidation-mode وفقًا لذلك. على سبيل المثال، سيقوم هذا الأمر بتجميع جميع الوحدات في المجلد الحالي والمجلدات الفرعية في ما يسمى بالمتغير المعتمد على التجزئة:
$ python -m compileall --invalidation-mode checked-hash
تشرح الوثائق الرسمية الفرق بين الإصدارات المحددة وغير المحددة لملفات .pyc المستندة إلى التجزئة على النحو التالي:
بالنسبة لملفات .pyc المعتمدة على التجزئة، يتحقق بايثون من صحة ملف التخزين المؤقت عن طريق تجزئة الملف المصدر ومقارنة التجزئة الناتجة بالتجزئة الموجودة في ملف التخزين المؤقت. إذا وجد أن ملف التخزين المؤقت المعتمد على التجزئة غير صالح، يقوم بايثون بإعادة إنشائه ويكتب ملف تخزين مؤقت معتمد على التجزئة جديد. بالنسبة لملفات .pyc المعتمدة على التجزئة غير المعتمدة، يفترض بايثون ببساطة أن ملف التخزين المؤقت صالح إذا كان موجودًا. (المصدر)
ومع ذلك، يمكنك دائمًا تجاوز سلوك التحقق الافتراضي لملفات .pyc المستندة إلى التجزئة باستخدام خيار --check-hash-based-pycs
عند تشغيل مُفسّر بايثون.
إن معرفة متى وأين يقوم بايثون بإنشاء مجلدات __pycache__، بالإضافة إلى متى يقوم بتحديث محتواها، سيعطيك فكرة عما إذا كان من الآمن إزالتها.
هل من الآمن إزالة مجلد ذاكرة التخزين المؤقت؟
نعم، ولكن يجب أن تسأل نفسك ما إذا كان ينبغي لك فعل ذلك حقًا! في هذه المرحلة، ستدرك أن إزالة مجلد __pycache__ غير ضار لأن بايثون يجدد ذاكرة التخزين المؤقت عند كل استدعاء. على أي حال، فإن إزالة مجلدات ذاكرة التخزين المؤقت الفردية يدويًا مهمة شاقة. علاوة على ذلك، لن تستمر هذه المهمة إلا حتى المرة التالية التي تقوم فيها بتشغيل الكود الخاص بك.
ملاحظة: على الرغم من أنك لست بحاجة إلى إزالة مجلدات ذاكرة التخزين المؤقت في معظم الحالات، فمن الأفضل استبعادها من نظام التحكم في الإصدارات مثل Git، على سبيل المثال، عن طريق إضافة نمط ملف مناسب إلى ملف .gitignore الخاص بمشروعك. وعلاوة على ذلك، إذا لم يقم محرر التعليمات البرمجية الخاص بك بذلك بالفعل، فقد ترغب في تكوينه لإخفاء مثل هذه المجلدات من مستكشف الملفات لتجنب التشتيت.
الخبر السار هو أنه يمكنك أتمتة إزالة مجلدات ذاكرة التخزين المؤقت هذه من مشروعك إذا كنت تصر حقًا على ذلك، وهو ما ستفعله الآن.
كيفية إزالة كافة مجلدات ذاكرة التخزين المؤقت بشكل متكرر؟
حسنًا، لقد ثبت بالفعل أن إزالة البايت كود المخزن المؤقت الذي يجمعه بايثون ليس بالأمر الصعب. ومع ذلك، فإن المشكلة مع مجلدات __pycache__ هذه هي أنها قد تظهر في أدلة فرعية متعددة إذا كان لديك بنية مشروع معقدة. سيكون العثور عليها وحذفها يدويًا مهمة شاقة، خاصة أنها تنهض مثل طائر الفينيق من الرماد في كل مرة تقوم فيها بتشغيل بايثون.
فيما يلي، ستجد الأوامر الخاصة بالمنصة التي تزيل بشكل متكرر جميع مجلدات __pycache__ من الدليل الحالي وجميع الدلائل الفرعية المتداخلة فيه دفعة واحدة:
PS> $dirs = Get-ChildItem -Path . -Filter __pycache__ -Recurse -Directory
PS> $dirs | Remove-Item -Recurse -Force
يجب عليك توخي الحذر عند تشغيل أوامر الحذف المجمعة، حيث يمكنها إزالة أكثر مما كنت تنوي إذا لم تكن حذرًا. تأكد دائمًا من المسارات ومعايير التصفية قبل تنفيذ مثل هذه الأوامر!
قد يؤدي حذف مجلدات __pycache__ إلى إزالة الفوضى من مساحة عمل مشروعك، ولكن مؤقتًا فقط. إذا كنت لا تزال منزعجًا من الاضطرار إلى تشغيل أمر الحذف المتكرر بشكل متكرر، فقد تفضل أن تتولى التحكم في التعامل مع مجلد ذاكرة التخزين المؤقت في المقام الأول. بعد ذلك، ستستكشف طريقتين لمعالجة هذه المشكلة.
كيفية منع بايثون من إنشاء مجلدات ذاكرة التخزين المؤقت؟
إذا كنت لا تريد أن يقوم بايثون بتخزين البايت كود المجمّع مؤقتًا، فيمكنك تمرير الخيار -B
إلى أمر python عند تشغيل البرنامج النصي. سيمنع هذا ظهور مجلدات __pycache__ ما لم تكن موجودة بالفعل. ومع ذلك، سيستمر بايثون في الاستفادة من أي ملفات .pyc
يمكنه العثور عليها في مجلدات التخزين المؤقت الموجودة. لن يكتب ملفات جديدة على القرص.
للحصول على تأثير أكثر ديمومة يمتد عبر العديد من مفسرين بايثون، يمكنك تعيين متغير البيئة PYTHONDONTWRITEBYTECODE في واجهة أوامر أو ملف الإعدادات الخاص به:
export PYTHONDONTWRITEBYTECODE=1
سيؤثر ذلك على أي مترجم بايثون، بما في ذلك المترجم الموجود داخل بيئة افتراضية قمت بتنشيطها.
مع ذلك، يجب أن تفكر مليًا فيما إذا كان قمع تجميع البايت كود هو النهج الصحيح لحالة الاستخدام الخاصة بك. البديل هو إخبار بايثون بإنشاء مجلدات __pycache__ الفردية في موقع مشترك واحد على نظام الملفات الخاص بك.
كيفية تخزين ذاكرة التخزين المؤقت في مجلد مركزي؟
عندما تقوم بتعطيل تجميع البايت كود بالكامل، فإنك تحصل على مساحة عمل أنظف ولكنك تفقد فوائد التخزين المؤقت لأوقات تحميل أسرع. إذا كنت ترغب في الجمع بين أفضل ما في ذلك، فيمكنك توجيه بايثون لكتابة ملفات .pyc في شجرة موازية متجذرة في الدليل المحدد باستخدام خيار -X pycache_prefix
:
$ python -X pycache_prefix=/tmp/pycache calculator.py
في هذه الحالة، يمكنك إخبار بايثون بتخزين الكود الثنائي المجمّع في مجلد مؤقت يقع في /tmp/pycache
على نظام الملفات الخاص بك. عند تشغيل هذا الأمر، لن يحاول بايثون إنشاء مجلدات __pycache__ محلية في مشروعك بعد الآن. بدلاً من ذلك، سيعكس بنية الدليل الخاصة بمشروعك ضمن المجلد الجذر المشار إليه ويخزن جميع ملفات .pyc هناك:
tmp/
└── pycache/
└── home/
└── user/
│
├── other_project/
│ └── solver.cpython-312.pyc
│
└── project/
│
└── mathematics/
│
├── arithmetic/
│ ├── __init__.cpython-312.pyc
│ ├── add.cpython-312.pyc
│ └── sub.cpython-312.pyc
│
├── geometry/
│ ├── __init__.cpython-312.pyc
│ └── shapes.cpython-312.pyc
│
└── __init__.cpython-312.pyc
لاحظ شيئين هنا. أولاً، نظرًا لأن دليل ذاكرة التخزين المؤقت منفصل عن الكود المصدر، فلا توجد حاجة إلى تعشيش ملفات .pyc المترجمة داخل مجلدات __pycache__
ثانيًا، نظرًا لأن التسلسل الهرمي داخل ذاكرة التخزين المؤقت المركزية هذه يتطابق مع بنية مشروعك، فيمكنك مشاركة مجلد ذاكرة التخزين المؤقت هذا بين مشاريع متعددة.
تتضمن المزايا الأخرى لهذا الإعداد سهولة التنظيف، حيث يمكنك إزالة جميع ملفات .pyc التي تنتمي إلى نفس المشروع بضغطة زر واحدة دون الحاجة إلى التنقل يدويًا عبر جميع الدلائل. بالإضافة إلى ذلك، يمكنك تخزين مجلد ذاكرة التخزين المؤقت على قرص مادي منفصل للاستفادة من القراءات المتوازية، أو الاحتفاظ بذاكرة التخزين المؤقت في وحدة تخزين دائمة عند العمل مع حاويات Docker.
تذكر أنه يجب عليك استخدام خيار -X pycache_prefix
في كل مرة تقوم فيها بتشغيل أمر python حتى يعمل هذا بشكل متسق. كبديل، يمكنك تعيين المسار إلى مجلد ذاكرة التخزين المؤقت المشتركة من خلال متغير البيئة PYTHONPYCACHEPREFIX:
export PYTHONPYCACHEPREFIX=/tmp/pycache
في كلتا الحالتين، يمكنك التحقق برمجيًا مما إذا كان بايثون سيستخدم دليل التخزين المؤقت المحدد أو يعود إلى السلوك الافتراضي وينشئ مجلدات __pycache__ محلية:
>>> import sys
>>> sys.pycache_prefix
'/tmp/pycache'
يمكن أن يكون المتغير sys.pycache_prefix عبارة عن سلسلة أو None.
لقد قطعت شوطًا طويلاً من خلال هذا البرنامج التعليمي، والآن تعرف شيئًا أو اثنين عن التعامل مع مجلدات __pycache__
في مشاريع بايثون الخاصة بك.
في هذا البرنامج التعليمي، تعمقت في تفاصيل آلية تخزين البايت كود في بايثون. والآن أصبحت تدرك أن التخزين المؤقت يتعلق بالوحدات التي تستوردها. فمن خلال تخزين البايت كود المجمّع في مجلدات __pycache__، يتجنب بايثون التكلفة الزائدة لإعادة تجميع الوحدات في كل تشغيل للبرنامج، مما يؤدي إلى أوقات بدء تشغيل أسرع.
الآن، أنت تفهم ما الذي يؤدي إلى إنشاء مجلدات ذاكرة التخزين المؤقت، وكيفية منعها، وكيفية نقلها إلى مجلد مركزي على نظام الملفات الخاص بك.
اكتشاف المزيد من بايثون العربي
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.