السلام عليكم ورحمة الله وبركاته
برنامجك أو بُرَيمجك الذي تكتبه، بأي لغة برمجة كانت، سواء Python أو Rust أو ++C أو C وغيرها، ليس إلا كومة تعليمات، رماز code، إن شغلته فهو كما هو، لا يتغير بين فينة وأخرى.
لكنه عند عمله سيهتم ببعض الأشياء، مثل معلومات المستخدم للولوج، أو أشياء تخص قاعدة المعطيات database، ومئات الأشياء المختلفة، وتلك الأشياء تتغير بتغير المكان الذي تعمل به، باختلاف البيئة environment التي يعمل بها. فلما يعمل على حاسوب عبود فسيطلب معلومات تخصه، وهي معلومات تختلف عن معلومات هشام، فالبيئة تختلف.
لذا عزيزي المبرمج عليك عند البرمجة أن تفصل بين الأشياء التي لن تتغير وهي ثابتة، وهي رمازك المكتوب code، وبين الأشياء المتغيرة، وهي البيئة التي سيعمل بها.
لكن كيف يا مبعسس، كيف نفصلها في بايثون، أما تفصِّل الشرح!
قبل أن أخبرك فعلي التوطئة بمفهوم تقدم ذكره، إلا وهو البيئة، فما هي؟
ما هي البيئة!

في سياق علوم الحاسوب فمصطلح البيئة: إعدادات البرنامج التي تحدد ظروف العمل وسلوكه، وهو يشمل العديد من المكونات والإعدادات التي تؤثر على كيفية تشغيل البرامج وتفاعلها مع النظام.
تمتاز الأنظمة الشبيهة بيونِكس Unix-Like بميزة للتعامل مع هذه الإعدادات الخاصة بالبيئة التي تؤثر في سلوك البرنامج، واسمها متغيرات البيئة environment variables. وما متغيرات البيئة إلا قيم values يستطيع أي برنامج قراءتها في أي وقت، واستعمالها لأي شأن يريده، فهو يعمل داخل هذه البيئة وله الحق في قراءتها متى ما أراد.
أنواع متغيرات البيئة
متغيرات البيئة تلك تنقسم إلى نوعين:
١. متغيرات عامة global: يستطيع أي برنامج في النظام قراءتها واستعمالها وحتى تغيير محتواها
٢. متغيرات خاصة private: متغيرات خاصة ببرنامج بعينه، لا يصل لها غيره.
هب أنك تبرمج برنامجًا، وأنت بحاجة إلى متغيرات البيئة تلك لبعض الأغراض من اختبار وتطوير وغيره…
أول عقبة أمامنا ستكون: إدارة هذه المتغيرات محليًا locally دون إعاقة لباقي البرمجيات التي تعمل، كأن يكون فيه برمجية تعمل وتستعمل نفس اسم المتغير، فيحدث تضارب.
ولحل تلك المسألة أتى ملف .env!
ملف يخزن متغيرات البيئة الخاصة ببرنامج معين.
ميزات استعمال .env

لاستعمال ملف .env في برنامجك المكتوب بلغة البرمجة بايثون محاسن عدة، نذكر منها:
١. الأمان: تخزين المعلومات المهمة، مثل كلمات المرور والرموز tokens يؤمن برنامجك بفصل المعلومات المهمة في ملف منفصل، وهذا مهم عند التعاون في المشاريع.
٢. سهولة القراءة والصيانة: هذا أمر بالغ الأهمية، لكونه ينظم الرِّماز ويرتبه، بفصل ما يجيب فصله، ليَحسُنَ فَهمه وإصلاح الأخطاء إن وجدت أو إضافة ميزات جديدة.
٣. المرونة: إذ يمكنك مشاركته بين أعضاء الفريق للتعاون، وتشغيله في أي بيئة.
مكتبة python-dotenv وتحميلها
ها قد أتينا إلى العملي بعد رحلة نظرية وجب التوطئة بها، فالفهم النظري ليس بمعزل عن التطبيق العملي.
كيف نستعمل ملف .env يا مبعسس؟
اشرح لنا!
حسنًا، حسنًا. لاستعمال ملف .env في برنامجك المكتوب بلغة بايثون فإننا بحاجة إلى مكتبة اسمها python-dotenv، وهذا أمر تثبيتها:
pip3 install python-dotenv
هذه المكتبة تقرأ محتويات ملف .env، التي هي متغيرات، وثم تدرجها إلى متغيرات البيئة، ليستطيع البرنامج استعمالها من ضمن باقي متغيرات البيئة.
وصيغة متغيرات الملف .env: المتغيرات التي يحويها الملف تكون بصيغة المفتاح والقيمة، كما القموس dictionary:
KEY=VALUE
وظيفة load_dotenv
مكتبة python-dotenv تحوي وظيفة ادراج ملف .env، اسمها load_dotenv.
نستعملها كما يلي:
from dotenv import load_dotenv
import os
load_dotenv()
api_id = os.getenv("API_ID")
لنشرح الرماز:
١. أول سطر: استدعاء للوظيفة load_dotenv من المكتبة
٢. ثاني سطر: استدعاء لمكتبة اسمها نظام التشغيل os، وهي مكتبة تقدم وظائف عدة للتعامل مع نظام التشغيل
٣. السطر الرابع (إن حسبنا المسافة): تشغيل للوظيفة load_dotenv، وبتشغيلها ستدرج محتويات الملف .env إلى متغيرات البيئة.
٤. السطر الأخير: جلب قيمة متغير البيئة المسمى API_ID، بالوظيفة getenv التي في المكتبة os، وهذه الوظيفة getenv: تجلب قيمة متغير البيئة التي تتلقاها.
باستعمال الوظيفة load_dotenv دون أي معاملات parameters فإنها ستبحث عن الملف .env باستعمال وظيفة أخرى مضمنة في المكتبة اسمها find_dotenv.
معاملات الوظيفة load_dotenv:
load_dotenv(dotenv_path=None, stream=None, verbose=False, override=False, interpolate=True, encoding='utf-8')
مسار ملف المتغيرات dotenv_path: وهو المسار حيث يكون ملف المتغيرات فيه، قيمته الافتراضية None.
الدفقة stream: يمكن وظيفة load_dotenv من استقبال دفقة دخل input stream لملف المتغيرات من مكان آخر، مثل الشبكة.
مسهب verbose: من اسمه أيها العربي، يظهر رسائل مفهومة تبين الخطأ، وقيمته الافتراضية False. إن كان True سيظهر رسالة تخبرنا أن ملف .env مفقود.
تجاوز override: قيمته الافتراضية لا False، وهذا يخبر وظيفة load_dotenv هل يتجاوز على المتغيرات التي لديها نفس الاسم أم لا؟
أي لو فيه متغيرات بنفس الاسم هل يجب أن تحل محل متغير آخر أم لا.
الترميز encoding: وقيمته الافتراضية UTF-8.
لنرى استعمالا عن الدفقة stream:
from io import StringIO
from dotenv import load_dotenv
config = StringIO("USER=narsus\[email protected]")
load_dotenv(stream=config)
وظيفة dotenv_values
كما رأيت في الوظيفة load_dotenv، فإنها تدرج المتغيرات في الملف إلى متغيرات البيئة، لكن ماذا لو أردت أن تُرجَع المحتويات على شكل قاموس تستعمله لأي غرض أردت؟
هنا تأتي الوظيفة dotenv_values التي ترجع قاموسا dict، ومعاملاتها التي تتلقاها هي هي التي في load_dotenv.
مثال:
from dotenv import dotenv_values
# Load the values from the .env file
config = dotenv_values(".env")
# Access the values
db_host = config["DB_HOST"]
db_port = config["DB_PORT"]
db_user = config["DB_USER"]
db_password = config["DB_PASSWORD"]
# Use the values in your code
print(f"Connecting to database at {db_host}:{db_port}")
# ... rest of your code ...
وظيفة find_dotenv
هذه الوظيفة تبحث عن ملف .env إن لم يكن في المجلد الحالي، فإن وجدته سترجع مساره، وإن لم تجده سترجع قيمة نصية فارغة.
مثال:
from dotenv import find_dotenv, dotenv_values
# Find the .env file
dotenv_path = find_dotenv()
# Load the values from the .env file
config = dotenv_values(dotenv_path)
# Access the values
db_host = config["DB_HOST"]
db_port = config["DB_PORT"]
db_user = config["DB_USER"]
db_password = config["DB_PASSWORD"]
# Use the values in your code
print(f"Connecting to database at {db_host}:{db_port}")
# ... rest of your code ...
وظيفة get_key
هب أنك تريد قيمة واحدة لا غير من ملف .env، لأي غرض، ولا تريد المتغيرات كلها، ستستعمل وظيفة get_key التي وظيفتها استخراج قيمة واحدة لا غير.
معاملات الوظيفة get_key:
get_key(dotenv_path, key_to_get, encoding='utf-8')
مسار الملف dotenv_path: كما سبق قوله، مسار الملف المطلوب أين هو.
المتغير المطلوب key_to_get: المتغير المطلوب جلب قيمته من الملف.
وظيفة set_key
هب أنك تريد إضافة قيمة أن تغيير قيمة قديمة في الملف، فما أنت فاعل؟
هنا تأتي وظيفة set_key، ومعاملاتها:
set_key(dotenv_path, key_to_set, value_to_set, quote_mode='always', export=False, encoding='utf-8')
مسار الملف
المتغير المراد تغييره key_to_set
القيمة التي ستضعها للمتغير value_to_set
الاقتباس quote_mode: قيمة تبين كيف ستُمَثَّل القيمة في الملف، فهل ستُقتَبس أم لا؟
لها ثلاث قيم لا ثالث لها:
دائمًا always: اجعلها دومًا في علامة اقتباس.
أبدًا never: لن تقتبس هذه القيمة أبدًا.
تلقائيًا auto: ستحدد الوظيفة هل ستُقتَبس القيمة أم لا، مثلا لو في القيمة محارف خاصة يجب وضعها في علامة اقتباس.
وظيفة unset_key
هذه الوظيفة الضد من وظيفة set_key، فهي تحذف متغيرا من متغيرات البيئة التي في الملف.
معاملاته:
unset_key(dotenv_path, key_to_unset, quote_mode='always', encoding='utf-8')
مسار الملف
المتغير المراد حذفه key_to_unset
الاقتباس quote_mode: وسبق شرحه
الخاتمة
وها أنا أخط بقلمي الخطوط الأخيرة لهذا المقال، وأرجو إني قد وفِّقت في الشرح.
وفي نهاية الأمر لا يسعني سوى أن أشكرك على حسن قراءتك لهذا المقال، وأني لبشر أصيب وأخطِئ، فإن وفِّقت في طرح الموضوع فمن اللّٰه عز وجل وإن أخفقت فمن نفسي والشيطان.
أرجو منك تقييم كفاءة المعلومات من أجل تزويدي بالملاحظات والنقد البناء في خانة التعليقات أو عبر حساب الموقع، والسلام عليكم ورحمة اللّٰه تعالى وبركاته.