دليل بايثون الشامل للمبتدئين: رحلتك الأولى في عالم البرمجة
أصبحت لغة بايثون (Python) واحدة من أسرع لغات البرمجة نموًا خلال السنوات القليلة الماضية. لا تقتصر شعبيتها على انتشارها الواسع فحسب، بل هي أيضًا لغة رائعة لاكتشافها إذا كنت ترغب في الانغماس في عالم البرمجة. يهدف هذا الدليل المخصص للمبتدئين إلى تمكينك من استيعاب جوهر اللغة في غضون ساعات قليلة بدلاً من أسابيع.
معلومة سريعة: يمكنك تنزيل نسخة PDF من دليل بايثون للمبتدئين هذا. هل أنت مستعد للانطلاق؟
جدول المحتويات
- مقدمة إلى لغة بايثون
- تثبيت بايثون 3
- تشغيل الأكواد البرمجية
- قواعد بناء الجمل (Syntax)
- التعليقات (Comments)
- المتغيرات (Variables)
- أنواع البيانات (Types)
- تحويل الأنواع (Typecasting)
- إدخال المستخدم (User Input)
- المعاملات (Operators)
- الجمل الشرطية (Conditionals)
- القوائم (Lists)
- المجموعات الثابتة (Tuples)
- المجموعات (Sets)
- القواميس (Dictionaries)
- حلقات التكرار
while - حلقات التكرار
for - الدوال (Functions)
- نطاق المتغيرات (Scope)
- فهم القوائم (List Comprehensions)
- دوال لامدا (Lambda Functions)
- الوحدات البرمجية (Modules)
- فهم
if __name__ == '__main__' - التعامل مع الملفات (Files)
- الفئات والكائنات (Classes and Objects)
- الوراثة (Inheritance)
- الاستثناءات (Exceptions)
- الخلاصة التقنية
مقدمة إلى لغة بايثون
تم إنشاء لغة بايثون (Python) في عام 1990 على يد Guido van Rossum في هولندا. كان أحد الأهداف الرئيسية للغة هو أن تكون سهلة الوصول لغير المبرمجين. كما صُممت بايثون لتكون لغة ثانية للمبرمجين لتعلمها نظرًا لمنحنى التعلم المنخفض وسهولة الاستخدام. تعمل بايثون على أنظمة Mac و Linux و Windows والعديد من الأنظمة الأساسية الأخرى.
تتميز بايثون بالخصائص التالية:
- لغة مفسرة (
Interpreted): يمكنها التنفيذ في وقت التشغيل، وتكون التغييرات في البرنامج ملحوظة على الفور. من الناحية التقنية، تحتوي بايثون على مترجم (compiler)، لكن الفرق مقارنة بلغات مثلJavaأوC++يكمن في مدى شفافية وعفوية عملية الترجمة. مع بايثون، لا داعي للقلق بشأن خطوة الترجمة حيث تتم في الوقت الفعلي. المقايضة هنا هي أن اللغات المفسرة عادة ما تكون أبطأ من اللغات المترجمة. - ديناميكية دلاليًا (
Semantically Dynamic): لا تحتاج إلى تحديد أنواع المتغيرات، ولا يوجد ما يجبرك على ذلك. - موجّهة الكائنات (
Object-Oriented): كل شيء في بايثون هو كائن (object). ولكن يمكنك اختيار كتابة الكود بطريقة موجهة الكائنات، أو إجرائية (procedural)، أو حتى وظيفية (functional). - عالية المستوى (
High level): لا تحتاج إلى التعامل مع تفاصيل الآلة منخفضة المستوى.
شهدت بايثون نموًا كبيرًا مؤخرًا، ويرجع ذلك جزئيًا إلى استخداماتها المتعددة في المجالات التالية:
- برمجة الأنظمة (
System scripting): أداة رائعة لأتمتة المهام المتكررة اليومية. - تحليل البيانات (
Data Analysis): لغة ممتازة للتجريب وتحتوي على عدد كبير من المكتبات والأدوات لمعالجة البيانات، وإنشاء النماذج، وتصور النتائج، وحتى نشر الحلول. تُستخدم هذه في مجالات مثل التمويل، والتجارة الإلكترونية، والبحث العلمي. - تطوير الويب (
Web Development): تسمح أطر العمل مثلDjangoوFlaskبتطوير تطبيقات الويب، واجهات برمجة التطبيقات (APIs)، والمواقع الإلكترونية. - التعلم الآلي (
Machine Learning): تُعدTensorflowوPytorchبعضًا من المكتبات التي تسمح للعلماء والصناعة بتطوير ونشر حلول الذكاء الاصطناعي في مجالات التعرف على الصور، والصحة، والسيارات ذاتية القيادة، والعديد من المجالات الأخرى.
يمكنك بسهولة تنظيم الكود الخاص بك في وحدات (modules) وإعادة استخدامها أو مشاركتها مع الآخرين.
أخيرًا، يجب أن نضع في اعتبارنا أن بايثون شهدت تغييرات جذرية بين الإصدارين Python 2 و Python 3. وبما أن دعم Python 2 انتهى في عام 2020، فإن هذا المقال يعتمد كليًا على Python 3. لذا، دعنا نبدأ.
تثبيت بايثون 3
إذا كنت تستخدم نظام Mac أو Linux، فلديك بايثون مثبتة بالفعل. لكن نظام Windows لا يأتي مع بايثون مثبتة افتراضيًا. قد يكون لديك أيضًا Python 2، ونحن سنستخدم Python 3. لذا، يجب عليك التحقق أولاً مما إذا كان لديك Python 3. اكتب ما يلي في الطرفية (terminal) الخاصة بك:
python3 -V
لاحظ حرف V الكبير. إذا كانت نتيجتك مشابهة لـ ‘Python 3.x.y‘، على سبيل المثال، Python 3.8.1، فأنت جاهز للانطلاق. إذا لم يكن الأمر كذلك، اتبع التعليمات التالية وفقًا لنظام التشغيل الخاص بك.
تثبيت بايثون 3 على نظام ويندوز (Windows)
- اذهب إلى https://www.python.org/downloads/.
- قم بتنزيل أحدث إصدار.
- بعد التنزيل، انقر نقرًا مزدوجًا على برنامج التثبيت.
- في الشاشة الأولى، ضع علامة في المربع الذي يشير إلى “
Add Python 3.x to PATH” ثم انقر على “Install Now“. - انتظر حتى تنتهي عملية التثبيت حتى تظهر الشاشة التالية برسالة “
Setup was successful“. - انقر على “
Close“.
تثبيت بايثون 3 على نظام ماك (Mac)
- قم بتثبيت
XCodeمن متجر التطبيقات (App Store). - قم بتثبيت أدوات سطر الأوامر (
command line tools) عن طريق تشغيل ما يلي في الطرفية (terminal) الخاصة بك:
xcode-select --install
- أوصي باستخدام
Homebrew. اذهب إلى https://brew.sh/ واتبع التعليمات في الصفحة الأولى لتثبيته. - بعد تثبيت
Homebrew، قم بتشغيل أوامرbrewالتالية لتثبيتPython 3:
brew update
brew install python3
يقوم Homebrew بالفعل بإضافة Python 3 إلى المسار (PATH)، لذلك لا داعي لفعل أي شيء آخر.
تثبيت بايثون 3 على نظام لينكس (Linux)
- للتثبيت باستخدام
apt، المتاح فيUbuntuوDebian، أدخل ما يلي:
sudo apt install python3
- للتثبيت باستخدام
yum، المتاح فيRedHatوCentOS، أدخل ما يلي:
sudo yum install python3
تشغيل الأكواد البرمجية
يمكنك تشغيل كود بايثون مباشرة في الطرفية (terminal) كأوامر، أو يمكنك حفظ الكود في ملف بامتداد .py وتشغيل ملف بايثون.
التشغيل مباشرة في الطرفية (Terminal)
يوصى بتشغيل الأوامر مباشرة في الطرفية عندما ترغب في تنفيذ شيء بسيط. افتح سطر الأوامر واكتب python3:
renan@mypc:~$ python3
يجب أن ترى شيئًا كهذا في الطرفية الخاصة بك يشير إلى الإصدار (في هذه الحالة، Python 3.6.9)، ونظام التشغيل (Linux)، وبعض الأوامر الأساسية للمساعدة. تشير >>> إلى أننا في وحدة تحكم بايثون (Python console).
Python 3.6.9 (default, Nov 7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
دعنا نختبر ذلك بتشغيل برنامجنا الأول لإجراء عملية حسابية بسيطة وجمع رقمين:
>>> 2 + 2
الناتج هو:
4
للخروج من وحدة تحكم بايثون، ما عليك سوى كتابة exit():
>>> exit()
تشغيل ملفات .py
إذا كان لديك برنامج معقد، يحتوي على العديد من أسطر الكود، فإن وحدة تحكم بايثون ليست الخيار الأفضل. البديل هو ببساطة فتح محرر نصوص، وكتابة الكود، وحفظ الملف بامتداد .py. دعنا نفعل ذلك، أنشئ ملفًا باسم second_program.py بالمحتوى التالي:
print('Second Program')
تقوم دالة print() بطباعة رسالة على الشاشة. توضع الرسالة داخل الأقواس باستخدام علامات اقتباس مفردة أو مزدوجة، وكلاهما يعمل بنفس الطريقة. لتشغيل البرنامج، في الطرفية الخاصة بك، قم بما يلي:
renan@mypc:~$ python3 second_program.py
الناتج هو:
Second Program
قواعد بناء الجمل (Syntax)
تشتهر بايثون بقواعد بناء جمل نظيفة. تتجنب اللغة استخدام الأحرف غير الضرورية للإشارة إلى بعض الخصوصيات.
الفواصل المنقوطة (Semicolons)
لا تستخدم بايثون الفواصل المنقوطة (;) لإنهاء الأسطر. سطر جديد يكفي لإخبار المفسر (interpreter) أن أمرًا جديدًا يبدأ. ستقوم دالة print() بعرض شيء ما. في هذا المثال، لدينا أمران سيعرضان الرسائل داخل علامات الاقتباس المفردة:
print('First command')
print('Second command')
الناتج:
First command
Second command
لكن ما يلي خاطئ بسبب الفواصل المنقوطة في النهاية:
print('First command');
print('Second command');
المسافات البادئة (Indentation)
تستخدم العديد من اللغات الأقواس المتعرجة (curly-brackets) لتحديد النطاق (scope). يستخدم مفسر بايثون المسافات البادئة فقط لتحديد متى ينتهي نطاق ويبدأ آخر. هذا يعني أنه يجب أن تكون على دراية بالمسافات البيضاء في بداية كل سطر – فهي ذات معنى وقد تؤدي إلى كسر الكود الخاص بك إذا وُضعت في غير مكانها. هذا التعريف لدالة يعمل بشكل صحيح:
def my_function():
print('First command')
هذا لا يعمل لأن المسافة البادئة للسطر الثاني مفقودة وسوف يلقي خطأ:
def my_function():
print('First command')
حساسية حالة الأحرف والمتغيرات
بايثون حساسة لحالة الأحرف (case sensitive). لذا فإن المتغيرين name و Name ليسا نفس الشيء ويخزنان قيمًا مختلفة.
name = 'Renan'
Name = 'Moura'
كما ترى، يتم إنشاء المتغيرات بسهولة بمجرد إسناد قيم إليها باستخدام الرمز =. هذا يعني أن name يخزن ‘Renan‘ وأن Name يخزن ‘Moura‘.
التعليقات (Comments)
أخيرًا، لتعليق شيء ما في الكود الخاص بك، استخدم علامة الهاش #. الجزء المعلق لا يؤثر على تدفق البرنامج.
# this function prints something
def my_function():
print('First command')
كانت هذه مجرد نظرة عامة. ستصبح تفاصيل كل من هذه الأمور أوضح في الأقسام التالية مع الأمثلة والتفسيرات الأوسع.
كيفية كتابة التعليقات في بايثون
الغرض من التعليقات هو شرح ما يحدث في الكود. تُكتب التعليقات جنبًا إلى جنب مع الكود الخاص بك ولكنها لا تؤثر على تدفق برنامجك. عندما تعمل بمفردك، قد لا تشعر أن التعليقات شيء يجب عليك كتابته. بعد كل شيء، في الوقت الحالي، أنت تعرف أسباب كل سطر من الكود. ولكن ماذا لو انضم أشخاص جدد إلى مشروعك بعد عام، وكان المشروع يحتوي على 3 وحدات، كل منها بـ 10,000 سطر من الكود؟ فكر في الأشخاص الذين لا يعرفون شيئًا عن تطبيقك والذين يضطرون فجأة إلى صيانته أو إصلاحه أو إضافة ميزات جديدة.
تذكر، لا يوجد حل واحد لمشكلة معينة. طريقتك في حل الأشياء هي طريقتك وحدك. إذا طلبت من 10 أشخاص حل نفس المشكلة، فسيأتون بـ 10 حلول مختلفة. إذا كنت تريد أن يفهم الآخرون منطقك بالكامل، فإن تصميم الكود الجيد إلزامي، ولكن التعليقات جزء لا يتجزأ من أي قاعدة كود.
بنية التعليقات في بايثون سهلة للغاية: ما عليك سوى استخدام رمز علامة الهاش # أمام النص الذي تريد أن يكون تعليقًا.
#This is a comment and it won't influence my program flow
يمكنك استخدام تعليق لشرح ما يفعله جزء من الكود.
#calculates the sum of any given two numbers
a + b
التعليقات متعددة الأسطر
ربما ترغب في التعليق على شيء معقد للغاية أو وصف كيفية عمل عملية ما في الكود الخاص بك. في هذه الحالات، يمكنك استخدام تعليقات متعددة الأسطر. للقيام بذلك، ما عليك سوى استخدام علامة هاش مفردة # لكل سطر.
#Everything after the hash mark
# is a comment
#This is a comment and it won't influence my program flow
#Calculates the cost of the project given variables a and b
#a is the time in months it will take until the project is finished
#b is how much money it will cost per month
a + b * 10
المتغيرات (Variables)
في أي برنامج، تحتاج إلى تخزين البيانات ومعالجتها لإنشاء تدفق أو منطق معين. هذا هو ما تستخدم له المتغيرات. يمكنك أن يكون لديك متغير لتخزين اسم، وآخر لتخزين عمر شخص، أو حتى استخدام نوع أكثر تعقيدًا لتخزين كل هذا مرة واحدة مثل القاموس (dictionary).
الإنشاء (التصريح)
تصريح المتغير هو عملية أساسية ومباشرة في بايثون. ما عليك سوى اختيار اسم وإسناد قيمة إليه باستخدام الرمز =.
name = 'Bob'
age = 32
يمكنك استخدام دالة print() لعرض قيمة المتغير.
print(name)
print(age)
Bob
32
لاحظ أنه في بايثون لا توجد كلمة خاصة للتصريح عن متغير. في اللحظة التي تسند فيها قيمة، يتم إنشاء المتغير في الذاكرة. تتمتع بايثون أيضًا بكتابة ديناميكية (dynamic typing)، مما يعني أنك لا تحتاج إلى إخبارها ما إذا كان المتغير الخاص بك نصًا أو رقمًا، على سبيل المثال. يستنتج المفسر النوع بناءً على القيمة المسندة. إذا كنت بحاجة إلى ذلك، يمكنك أيضًا إعادة التصريح عن متغير بمجرد تغيير قيمته.
#declaring name as a string
name = 'Bob'
#re-declaring name as an int
name = 32
ضع في اعتبارك، مع ذلك، أن هذا غير موصى به لأن المتغيرات يجب أن يكون لها معنى وسياق. إذا كان لدي متغير يسمى name، فلا أتوقع أن يحتوي على رقم مخزن فيه.
اصطلاحات التسمية (Naming Conventions)
دعنا نواصل من القسم الأخير عندما تحدثت عن المعنى والسياق. لا تستخدم أسماء متغيرات عشوائية مثل x أو y. قل إنك تريد تخزين وقت حفلة، فقط سمها party_time. أوه، هل لاحظت الشرطة السفلية (_)؟ حسب الاتفاقية، إذا كنت ترغب في استخدام اسم متغير يتكون من كلمتين أو أكثر، فافصل بينهما بشرطات سفلية. يسمى هذا Snake Case. خيار آخر هو استخدام CamelCase كما في partyTime. هذا شائع جدًا في اللغات الأخرى، لكنه ليس الاتفاقية في بايثون كما ذكرنا سابقًا. المتغيرات حساسة لحالة الأحرف، لذا party_time و Party_time ليسا نفس الشيء. تذكر أيضًا أن الاتفاقية تخبرنا دائمًا باستخدام الأحرف الصغيرة.
تذكر، استخدم أسماء يمكنك تذكرها بسهولة داخل برنامجك. التسمية السيئة يمكن أن تكلفك الكثير من الوقت وتسبب أخطاء مزعجة.
باختصار، أسماء المتغيرات:
- حساسة لحالة الأحرف:
timeوTIMEليسا نفس الشيء. - يجب أن تبدأ بشرطة سفلية
_أو حرف (لا تبدأ برقم). - يُسمح لها فقط بالأرقام والأحرف والشرطات السفلية. لا توجد أحرف خاصة مثل:
#،$،&،@، إلخ. هذا، على سبيل المثال، غير مسموح به:party#time،10partytime.
أنواع البيانات (Types)
لتخزين البيانات في بايثون، تحتاج إلى استخدام متغير. ولكل متغير نوعه الخاص اعتمادًا على قيمة البيانات المخزنة. تتمتع بايثون بكتابة ديناميكية، مما يعني أنك لا تحتاج إلى التصريح صراحة عن نوع المتغير الخاص بك – ولكن إذا أردت، يمكنك ذلك. القوائم (Lists)، والمجموعات الثابتة (Tuples)، والمجموعات (Sets)، والقواميس (Dictionaries) كلها أنواع بيانات ولها أقسام مخصصة لاحقًا بتفاصيل أكثر، ولكننا سنلقي نظرة عليها بإيجاز هنا. بهذه الطريقة يمكنني أن أريك أهم الجوانب والعمليات لكل منها في قسمها الخاص مع الحفاظ على هذا القسم أكثر إيجازًا وتركيزًا على إعطائك نظرة واسعة على أنواع البيانات الرئيسية في بايثون.
تحديد النوع
أولاً وقبل كل شيء، دعنا نتعلم كيفية تحديد نوع البيانات. ما عليك سوى استخدام دالة type() وتمرير المتغير الذي تختاره كوسيط (argument)، مثل المثال أدناه.
print(type(my_variable))
المنطقية (Boolean)
النوع المنطقي هو أحد أبسط أنواع البرمجة. يمكن لمتغير من النوع المنطقي أن يمثل إما True أو False فقط.
my_bool = True
print(type(my_bool))
my_bool = bool(1024)
print(type(my_bool))
<class 'bool'>
<class 'bool'>
الأرقام (Numbers)
هناك ثلاثة أنواع من الأرقام: الصحيحة (int)، العشرية (float)، والمعقدة (complex).
الأعداد الصحيحة (Integer)
my_int = 32
print(type(my_int))
my_int = int(32)
print(type(my_int))
<class 'int'>
<class 'int'>
الأعداد العشرية (Float)
my_float = 32.85
print(type(my_float))
my_float = float(32.85)
print(type(my_float))
<class 'float'>
<class 'float'>
الأعداد المركبة (Complex)
my_complex_number = 32 + 4j
print(type(my_complex_number))
my_complex_number = complex(32 + 4j)
print(type(my_complex_number))
<class 'complex'>
<class 'complex'>
السلاسل النصية (String)
النوع النصي هو أحد أكثر الأنواع شيوعًا ويُطلق عليه غالبًا string أو، في بايثون، str فقط.
my_city = "New York"
print(type(my_city))
#Single quotes have exactly
#the same use as double quotes
my_city = 'New York'
print(type(my_city))
#Setting the variable type explicitly
my_city = str("New York")
print(type(my_city))
<class 'str'>
<class 'str'>
<class 'str'>
يمكنك استخدام المعامل + لدمج السلاسل النصية (concatenate strings). الدمج هو عندما يكون لديك سلسلتان نصيتان أو أكثر وتريد ربطهما في سلسلة واحدة.
word1 = 'New '
word2 = 'York'
print(word1 + word2)
New York
يحتوي نوع السلسلة النصية على العديد من الدوال المدمجة (built-in methods) التي تتيح لنا معالجتها. سأوضح كيفية عمل بعض هذه الدوال.
دالة len() تُرجع طول السلسلة النصية.
print(len('New York'))
8
دالة replace() تستبدل جزءًا من السلسلة النصية بآخر. على سبيل المثال، دعنا نستبدل ‘New‘ بـ ‘Old‘.
print('New York'.replace('New', 'Old'))
Old York
دالة upper() ستُرجع جميع الأحرف كأحرف كبيرة (uppercase).
print('New York'.upper())
NEW YORK
دالة lower() تفعل العكس، وتُرجع جميع الأحرف كأحرف صغيرة (lowercase).
print('New York'.lower())
new york
القوائم (Lists)
القائمة (list) تحتوي على عناصر مرتبة ويمكنك إضافة نفس العنصر عدة مرات كما تريد. تفصيل مهم هو أن القوائم قابلة للتعديل (mutable). تعني قابلية التعديل أنه يمكنك تغيير القائمة بعد إنشائها عن طريق إضافة عناصر أو إزالتها أو حتى مجرد تغيير قيمها. سيتم توضيح هذه العمليات لاحقًا في القسم المخصص للقوائم.
my_list = ["bmw", "ferrari", "maclaren"]
print(type(my_list))
my_list = list(("bmw", "ferrari", "maclaren"))
print(type(my_list))
<class 'list'>
<class 'list'>
المجموعات الثابتة (Tuples)
المجموعة الثابتة (tuple) تشبه القائمة تمامًا: مرتبة، وتسمح بتكرار العناصر. هناك فرق واحد فقط: المجموعة الثابتة غير قابلة للتعديل (immutable). تعني عدم قابلية التعديل أنه لا يمكنك تغيير المجموعة الثابتة بعد إنشائها. إذا حاولت إضافة عنصر أو تحديثه، على سبيل المثال، سيعرض مفسر بايثون خطأ. سأوضح أن هذه الأخطاء تحدث لاحقًا في القسم المخصص للمجموعات الثابتة.
my_tuple = ("bmw", "ferrari", "maclaren")
print(type(my_tuple))
my_tuple = tuple(("bmw", "ferrari", "maclaren"))
print(type(my_tuple))
<class 'tuple'>
<class 'tuple'>
المجموعات (Sets)
المجموعات (Sets) لا تضمن ترتيب العناصر وليست مفهرسة. نقطة رئيسية عند استخدام المجموعات: لا تسمح بتكرار العنصر.
my_set = {"bmw", "ferrari", "maclaren"}
print(type(my_set))
my_set = set(("bmw", "ferrari", "maclaren"))
print(type(my_set))
<class 'set'>
<class 'set'>
القواميس (Dictionaries)
القاموس (dictionary) لا يضمن ترتيب العناصر وهو قابل للتعديل (mutable). إحدى الخصائص المهمة في القواميس هي أنه يمكنك تعيين مفاتيح الوصول الخاصة بك لكل عنصر.
my_dict = {"country": "France", "worldcups": 2}
print(type(my_dict))
my_dict = dict(country="France", worldcups=2)
print(type(my_dict))
<class 'dict'>
<class 'dict'>
تحويل الأنواع (Typecasting)
يسمح لك تحويل الأنواع (Typecasting) بالتحويل بين أنواع مختلفة. بهذه الطريقة يمكنك تحويل عدد صحيح (int) إلى سلسلة نصية (str)، أو عدد عشري (float) إلى عدد صحيح (int)، على سبيل المثال.
التحويل الصريح (Explicit Conversion)
لتحويل متغير إلى سلسلة نصية، ما عليك سوى استخدام دالة str().
# this is just a regular explicit intialization
my_str = str('32')
print(my_str)
# int to str
my_str = str(32)
print(my_str)
# float to str
my_str = str(32.0)
print(my_str)
32
32
32.0
لتحويل متغير إلى عدد صحيح، ما عليك سوى استخدام دالة int().
# this is just a regular explicit intialization
my_int = int(32)
print(my_int)
# float to int: rounds down to 3
my_int = int(3.2)
print(my_int)
# str to int
my_int = int('32')
print(my_int)
32
3
32
لتحويل متغير إلى عدد عشري، ما عليك سوى استخدام دالة float().
# this is an explicit intialization
my_float = float(3.2)
print(my_float)
# int to float
my_float = float(32)
print(my_float)
# str to float
my_float = float('32')
print(my_float)
3.2
32.0
32.0
ما فعلته أعلاه يسمى تحويلاً صريحًا للنوع. في بعض الحالات، لا تحتاج إلى إجراء التحويل صراحة، حيث يمكن لبايثون القيام بذلك بنفسها.
التحويل الضمني (Implicit Conversion)
يوضح المثال أدناه التحويل الضمني عند إضافة عدد صحيح (int) وعدد عشري (float). لاحظ أن my_sum هو من النوع float. تستخدم بايثون float لتجنب فقدان البيانات نظرًا لأن نوع int لا يمكنه تمثيل الأرقام العشرية.
my_int = 32
my_float = 3.2
my_sum = my_int + my_float
print(my_sum)
print(type(my_sum))
35.2
<class 'float'>
من ناحية أخرى، في هذا المثال، عند إضافة عدد صحيح (int) وسلسلة نصية (str)، لن تتمكن بايثون من إجراء التحويل الضمني، ويكون التحويل الصريح للنوع ضروريًا.
my_int = 32
my_str = '32'
# explicit conversion works
my_sum = my_int + int(my_str)
print(my_sum)
#implicit conversion throws an error
my_sum = my_int + my_str
64
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
يتم إطلاق نفس الخطأ عند محاولة إضافة أنواع float و str دون إجراء تحويل صريح.
my_float = 3.2
my_str = '32'
# explicit conversion works
my_sum = my_float + float(my_str)
print(my_sum)
#implicit conversion throws an error
my_sum = my_float + my_str
35.2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'float' and 'str'
إدخال المستخدم (User Input)
إذا كنت بحاجة إلى التفاعل مع مستخدم عند تشغيل برنامجك في سطر الأوامر (على سبيل المثال، لطلب معلومة)، يمكنك استخدام دالة input().
country = input("What is your country? ")
#user enters 'Brazil'
print(country)
Brazil
القيمة الملتقطة هي دائمًا سلسلة نصية (string). تذكر فقط أنك قد تحتاج إلى تحويلها باستخدام تحويل الأنواع (typecasting).
age = input("How old are you? ")
#user enters '29'
print(age)
print(type(age))
age = int(age)
print(type(age))
الناتج لكل print() هو:
29
<class 'str'>
<class 'int'>
لاحظ أن العمر 29 يتم التقاطه كسلسلة نصية (string) ثم يتم تحويله صراحة إلى عدد صحيح (int).
المعاملات (Operators)
في لغة البرمجة، المعاملات (operators) هي رموز خاصة يمكنك تطبيقها على متغيراتك وقيمك لإجراء عمليات مثل العمليات الحسابية والمقارنة. تحتوي بايثون على الكثير من المعاملات التي يمكنك تطبيقها على متغيراتك وسأوضح أكثرها استخدامًا.
المعاملات الحسابية (Arithmetic Operators)
المعاملات الحسابية هي النوع الأكثر شيوعًا من المعاملات وأيضًا الأكثر سهولة في التعرف عليها. تسمح لك بإجراء عمليات حسابية بسيطة. وهي:
+: الجمع (Addition)-: الطرح (Subtraction)*: الضرب (Multiplication)/: القسمة (Division)**: الرفع إلى الأس (Exponentiation)//: القسمة الصحيحة (Floor Division)، تقرب نتيجة القسمة إلى الأسفل%: المعامل (Modulus)، يعطيك باقي القسمة
دعنا نرى برنامجًا يوضح كيفية استخدام كل منها.
print('Addition:', 5 + 2)
print('Subtraction:', 5 - 2)
print('Multiplication:', 5 * 2)
print('Division:', 5 / 2)
print('Floor Division:', 5 // 2)
print('Exponentiation:', 5 ** 2)
print('Modulus:', 5 % 2)
Addition: 7
Subtraction: 3
Multiplication: 10
Division: 2.5
Floor Division: 2
Exponentiation: 25
Modulus: 1
الدمج (Concatenation)
الدمج هو عندما يكون لديك سلسلتان نصيتان أو أكثر وتريد ربطهما في سلسلة واحدة. هذا مفيد عندما يكون لديك معلومات في متغيرات متعددة وتريد دمجها. على سبيل المثال، في المثال التالي، أدمج متغيرين يحتويان على اسمي الأول واسمي الأخير على التوالي للحصول على اسمي الكامل. يستخدم المعامل + أيضًا للدمج.
first_name = 'Renan '
last_name = 'Moura'
print(first_name + last_name)
Renan Moura
بما أن الدمج يطبق على السلاسل النصية، لدمج السلاسل النصية بأنواع أخرى، يجب عليك إجراء تحويل صريح للنوع باستخدام str(). يجب علي تحويل قيمة العدد الصحيح 30 إلى سلسلة نصية باستخدام str() لدمجها مع بقية السلسلة النصية.
age = 'I have ' + str(30) + ' years old'
print(age)
I have 30 years old
معاملات المقارنة (Comparison Operators)
استخدم معاملات المقارنة لمقارنة قيمتين. تُرجع هذه المعاملات إما True أو False. وهي:
==: يساوي (Equal)!=: لا يساوي (Not equal)>: أكبر من (Greater than)<: أصغر من (Less than)>=: أكبر من أو يساوي (Greater than or equal to)<=: أصغر من أو يساوي (Less than or equal to)
دعنا نرى برنامجًا يوضح كيفية استخدام كل منها.
print('Equal:', 5 == 2)
print('Not equal:', 5 != 2)
print('Greater than:', 5 > 2)
print('Less than:', 5 < 2)
print('Greater than or equal to:', 5 >= 2)
print('Less than or equal to:', 5 <= 2)
Equal: False
Not equal: True
Greater than: True
Less than: False
Greater than or equal to: True
Less than or equal to: False
معاملات الإسناد (Assignment Operators)
كما يوحي الاسم، تُستخدم هذه المعاملات لإسناد قيم إلى المتغيرات. x = 7 في المثال الأول هو إسناد مباشر يخزن الرقم 7 في المتغير x. تأخذ عملية الإسناد القيمة الموجودة على اليمين وتسندها إلى المتغير الموجود على اليسار.
المعاملات الأخرى هي اختصارات بسيطة للمعاملات الحسابية. في المثال الثاني، يبدأ x بالقيمة 7 و x += 2 هي مجرد طريقة أخرى لكتابة x = x + 2. هذا يعني أن القيمة السابقة لـ x يتم زيادتها بمقدار 2 وإعادة إسنادها إلى x الذي يساوي الآن 9.
=: إسناد بسيط
x = 7
print(x)
7
+=: جمع وإسناد
x = 7
x += 2
print(x)
9
-=: طرح وإسناد
x = 7
x -= 2
print(x)
5
*=: ضرب وإسناد
x = 7
x *= 2
print(x)
14
/=: قسمة وإسناد
x = 7
x /= 2
print(x)
3.5
%=: معامل (باقي القسمة) وإسناد
x = 7
x %= 2
print(x)
1
//=: قسمة صحيحة وإسناد
x = 7
x //= 2
print(x)
3
**=: رفع إلى أس وإسناد
x = 7
x **= 2
print(x)
49
المعاملات المنطقية (Logical Operators)
تُستخدم المعاملات المنطقية لدمج العبارات بتطبيق الجبر البولياني (boolean algebra). وهي:
and: تُرجعTrueفقط عندما تكون كلتا العبارتين صحيحتين.or: تُرجعFalseفقط عندما تكون كلتا العبارتينxوyخاطئتين.not: المعاملnotببساطة يعكس المدخل،TrueيصبحFalseوالعكس صحيح.
دعنا نرى برنامجًا يوضح كيفية استخدام كل منها.
x = 5
y = 2
print(x == 5 and y > 3)
print(x == 5 or y > 3)
print(not (x == 5))
False
True
False
معاملات العضوية (Membership Operators)
توفر هذه المعاملات طريقة سهلة للتحقق مما إذا كان كائن معين موجودًا في تسلسل (sequence): string، list، tuple، set، و dictionary. وهي:
in: تُرجعTrueإذا كان الكائن موجودًا.not in: تُرجعTrueإذا لم يكن الكائن موجودًا.
دعنا نرى برنامجًا يوضح كيفية استخدام كل منها.
number_list = [1, 2, 4, 5, 6]
print(1 in number_list)
print(5 not in number_list)
print(3 not in number_list)
True
False
True
الجمل الشرطية (Conditionals)
الجمل الشرطية هي أحد الأركان الأساسية لأي لغة برمجة. تسمح لك بالتحكم في تدفق البرنامج وفقًا لشروط محددة يمكنك التحقق منها.
عبارة if
الطريقة التي تنفذ بها شرطًا هي من خلال عبارة if. الشكل العام لعبارة if هو:
if expression:
statement
تحتوي expression على بعض المنطق الذي يُرجع قيمة منطقية (boolean)، ويتم تنفيذ statement فقط إذا كانت النتيجة True. مثال بسيط:
bob_age = 32
sarah_age = 29
if bob_age > sarah_age:
print('Bob is older than Sarah')
Bob is older than Sarah
لدينا متغيران يشيران إلى أعمار بوب وسارة. الشرط باللغة الإنجليزية البسيطة يقول: "إذا كان عمر بوب أكبر من عمر سارة، فاطبع العبارة 'بوب أكبر من سارة'". بما أن الشرط يُرجع True، فسيتم طباعة العبارة في وحدة التحكم.
عبارات if else و elif
في مثالنا الأخير، يقوم البرنامج بشيء ما فقط إذا كان الشرط يُرجع True. لكننا نريده أيضًا أن يفعل شيئًا إذا كان يُرجع False أو حتى يتحقق من شرط ثانٍ أو ثالث إذا لم يتم استيفاء الشرط الأول. في هذا المثال، قمنا بتبديل أعمار بوب وسارة. سيعيد الشرط الأول False لأن سارة أكبر الآن، ثم سيطبع البرنامج العبارة بعد else بدلاً من ذلك.
bob_age = 29
sarah_age = 32
if bob_age > sarah_age:
print('Bob is older than Sarah')
else:
print('Bob is younger than Sarah')
Bob is younger than Sarah
الآن، لننظر إلى المثال أدناه مع elif.
bob_age = 32
sarah_age = 32
if bob_age > sarah_age:
print('Bob is older than Sarah')
elif bob_age == sarah_age:
print('Bob and Sarah have the same age')
else:
print('Bob is younger than Sarah')
Bob and Sarah have the same age
الغرض من elif هو توفير شرط جديد للتحقق منه قبل تنفيذ else. مرة أخرى غيرنا أعمارهما والآن كلاهما يبلغ من العمر 32 عامًا. على هذا النحو، يتم استيفاء الشرط في elif. بما أن كلاهما لهما نفس العمر، سيطبع البرنامج "بوب وسارة لهما نفس العمر". لاحظ أنه يمكنك أن يكون لديك أي عدد تريده من عبارات elif، فقط ضعها بالتسلسل.
bob_age = 32
sarah_age = 32
if bob_age > sarah_age:
print('Bob is older than Sarah')
elif bob_age < sarah_age:
print('Bob is younger than Sarah')
elif bob_age == sarah_age:
print('Bob and Sarah have the same age')
else:
print('This one is never executed')
Bob and Sarah have the same age
في هذا المثال، لا يتم تنفيذ else أبدًا لأن جميع الاحتمالات مغطاة في الشروط السابقة وبالتالي يمكن إزالتها.
الشروط المتداخلة (Nested Conditionals)
قد تحتاج إلى التحقق من أكثر من شرط واحد لحدوث شيء ما. في هذه الحالة، يمكنك تداخل عبارات if الخاصة بك. على سبيل المثال، يتم طباعة العبارة الثانية "بوب هو الأكبر" فقط إذا نجحت كلتا عبارتا if.
bob_age = 32
sarah_age = 28
mary_age = 25
if bob_age > sarah_age:
print('Bob is older than Sarah')
if bob_age > mary_age:
print('Bob is the oldest')
Bob is older than Sarah
Bob is the oldest
أو، اعتمادًا على المنطق، اجعلها أبسط باستخدام الجبر البولياني (Boolean Algebra). بهذه الطريقة، يكون الكود الخاص بك أصغر وأكثر قابلية للقراءة وأسهل في الصيانة.
bob_age = 32
sarah_age = 28
mary_age = 25
if bob_age > sarah_age and bob_age > mary_age:
print('Bob is the oldest')
Bob is the oldest
المعاملات الثلاثية (Ternary Operators)
المعامل الثلاثي هو عبارة if في سطر واحد. إنه مفيد جدًا للشروط البسيطة. يبدو كالتالي:
<expression> if <condition> else <expression>
لننظر إلى كود بايثون التالي:
a = 25
b = 50
x = 0
y = 1
result = x if a > b else y
print(result)
1
هنا نستخدم أربعة متغيرات، a و b للشرط، بينما x و y يمثلان التعبيرات. a و b هي القيم التي نتحقق منها مقابل بعضها البعض لتقييم شرط ما. في هذه الحالة، نتحقق مما إذا كان a أكبر من b. إذا كان التعبير صحيحًا، أي أن a أكبر من b، فسيتم إسناد قيمة x إلى result والتي ستكون مساوية لـ 0. ومع ذلك، إذا كان a أصغر من b، فسنحصل على قيمة y المسندة إلى result، وستحتوي result على القيمة 1. بما أن a أصغر من b، (25 < 50)، فإن result ستحتوي على 1 كقيمة نهائية من y.
الطريقة السهلة لتذكر كيفية تقييم الشرط هي قراءته باللغة الإنجليزية البسيطة. مثالنا سيقرأ: result ستكون x إذا كان a أكبر من b وإلا y.
القوائم (Lists)
كما وعدنا في قسم أنواع البيانات، سيحتوي هذا القسم والأقسام الثلاثة التالية حول المجموعات الثابتة، المجموعات، و القواميس على تفسيرات أكثر تفصيلاً لكل منها نظرًا لأهميتها واستخدامها الواسع في بايثون لتنظيم البيانات والتعامل معها.
القائمة (list) تحتوي على عناصر مرتبة ويمكنك إضافة نفس العنصر عدة مرات كما تريد. تفصيل مهم هو أن القوائم قابلة للتعديل (mutable). تعني قابلية التعديل أنه يمكنك تغيير القائمة بعد إنشائها عن طريق إضافة عناصر أو إزالتها أو حتى مجرد تغيير قيمها.
التهيئة (Initialization)
قائمة فارغة (Empty List)
people = []
قائمة ذات قيم أولية (List with initial values)
people = ['Bob', 'Mary']
الإضافة إلى قائمة (Adding in a List)
لإضافة عنصر في نهاية القائمة، استخدم دالة append().
people = ['Bob', 'Mary']
people.append('Sarah')
print(people)
['Bob', 'Mary', 'Sarah']
لتحديد موضع العنصر الجديد، استخدم دالة insert().
people = ['Bob', 'Mary']
people.insert(0, 'Sarah')
print(people)
['Sarah', 'Bob', 'Mary']
التحديث في قائمة (Updating in a List)
حدد موضع العنصر المراد تحديثه وقم بتعيين القيمة الجديدة.
people = ['Bob', 'Mary']
people[1] = 'Sarah'
print(people)
['Bob', 'Sarah']
الحذف من قائمة (Deleting in a List)
استخدم دالة remove() لحذف العنصر المعطى كوسيط.
people = ['Bob', 'Mary']
people.remove('Bob')
print(people)
['Mary']
لحذف جميع العناصر، استخدم دالة clear():
people = ['Bob', 'Mary']
people.clear()
الاسترجاع من قائمة (Retrieving in a List)
استخدم الفهرس (index) للإشارة إلى العنصر. تذكر أن الفهرس يبدأ من 0. لذا للوصول إلى العنصر الثاني، استخدم الفهرس 1.
people = ['Bob', 'Mary']
print(people[1])
Mary
التحقق من وجود عنصر في قائمة
people = ['Bob', 'Mary']
if 'Bob' in people:
print('Bob exists!')
else:
print('There is no Bob!')
المجموعات الثابتة (Tuples)
المجموعة الثابتة (tuple) تشبه القائمة: فهي مرتبة، وتسمح بتكرار العناصر. هناك فرق واحد فقط: المجموعة الثابتة غير قابلة للتعديل (immutable). عدم قابلية التعديل، إذا كنت تتذكر، يعني أنه لا يمكنك تغيير المجموعة الثابتة بعد إنشائها. إذا حاولت إضافة عنصر أو تحديثه، على سبيل المثال، سيعرض مفسر بايثون خطأ.
التهيئة (Initialization)
مجموعة ثابتة فارغة (Empty Tuple)
people = ()
مجموعة ثابتة ذات قيم أولية (Tuple with initial values)
people = ('Bob', 'Mary')
الإضافة إلى مجموعة ثابتة (Adding in a Tuple)
المجموعات الثابتة غير قابلة للتعديل. هذا يعني أنه إذا حاولت إضافة عنصر، سترى خطأ.
people = ('Bob', 'Mary')
people[2] = 'Sarah'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
التحديث في مجموعة ثابتة (Updating in a Tuple)
تحديث عنصر سيعيد أيضًا خطأ. ولكن هناك حيلة: يمكنك التحويل إلى قائمة، وتغيير العنصر، ثم تحويله مرة أخرى إلى مجموعة ثابتة.
people = ('Bob', 'Mary')
people_list = list(people)
people_list[1] = 'Sarah'
people = tuple(people_list)
print(people)
('Bob', 'Sarah')
الحذف من مجموعة ثابتة (Deleting in a Tuple)
للسبب نفسه الذي لا يمكنك من خلاله إضافة عنصر، لا يمكنك أيضًا حذف عنصر، لأنها غير قابلة للتعديل.
الاسترجاع من مجموعة ثابتة (Retrieving in a Tuple)
استخدم الفهرس للإشارة إلى العنصر.
people = ('Bob', 'Mary')
print(people[1])
Mary
التحقق من وجود عنصر في مجموعة ثابتة
people = ('Bob', 'Mary')
if 'Bob' in people:
print('Bob exists!')
else:
print('There is no Bob!')
المجموعات (Sets)
المجموعات (Sets) لا تضمن ترتيب العناصر وليست مفهرسة. نقطة رئيسية عند استخدام المجموعات: لا تسمح بتكرار العنصر.
التهيئة (Initialization)
مجموعة فارغة (Empty Set)
people = set()
مجموعة ذات قيم أولية (Set with initial values)
people = {'Bob', 'Mary'}
الإضافة إلى مجموعة (Adding in a Set)
استخدم دالة add() لإضافة عنصر واحد.
people.add('Sarah')
استخدم دالة update() لإضافة عناصر متعددة في وقت واحد.
people.update(['Carol', 'Susan'])
تذكر، المجموعات لا تسمح بالتكرار، لذا إذا أضفت 'Mary' مرة أخرى، فلن يتغير شيء.
people = {'Bob', 'Mary'}
people.add('Mary')
print(people)
{'Bob', 'Mary'}
التحديث في مجموعة (Updating in a Set)
العناصر في المجموعة غير قابلة للتعديل. يجب عليك إما إضافة أو حذف عنصر.
الحذف من مجموعة (Deleting in a Set)
لإزالة 'Bob' من المجموعة:
people = {'Bob', 'Mary'}
people.remove('Bob')
print(people)
{'Mary'}
لحذف جميع العناصر:
people.clear()
التحقق من وجود عنصر في مجموعة
people = {'Bob', 'Mary'}
if 'Bob' in people:
print('Bob exists!')
else:
print('There is no Bob!')
القواميس (Dictionaries)
القاموس (dictionary) لا يضمن ترتيب العناصر وهو قابل للتعديل (mutable). إحدى الخصائص المهمة في القواميس هي أنه يمكنك تعيين مفاتيح الوصول المخصصة الخاصة بك لكل عنصر.
تهيئة القاموس (Initialization of a Dictionary)
قاموس فارغ (Empty Dictionary)
people = {}
قاموس ذات قيم أولية (Dictionary with initial values)
people = {'Bob': 30, 'Mary': 25}
الإضافة إلى قاموس (Adding in a Dictionary)
إذا لم يكن المفتاح موجودًا بعد، يتم إلحاقه بالقاموس.
people['Sarah'] = 32
تحديث قاموس (Updating a Dictionary)
إذا كان المفتاح موجودًا بالفعل، يتم تحديث القيمة فقط.
#Bob's age is 28 now
people['Bob'] = 28
لاحظ أن الكود هو نفسه تقريبًا.
الحذف من قاموس (Deleting in a Dictionary)
لإزالة 'Bob' من القاموس:
people.pop('Bob')
لحذف جميع العناصر:
people.clear()
الاسترجاع من قاموس (Retrieving in a Dictionary)
bob_age = people['Bob']
print(bob_age)
30
التحقق من وجود مفتاح في قاموس
if 'Bob' in people:
print('Bob exists!')
else:
print('There is no Bob!')
حلقات التكرار while
تُستخدم حلقات التكرار (Loops) عندما تحتاج إلى تكرار كتلة من الكود عددًا معينًا من المرات أو تطبيق نفس المنطق على كل عنصر في مجموعة. هناك نوعان من حلقات التكرار: for و while. ستتعلم عن حلقات for في القسم التالي.
البنية الأساسية (Basic Syntax)
البنية الأساسية لحلقة while هي كما يلي.
while condition:
statement
ستستمر الحلقة طالما أن الشرط True. يوضح المثال أدناه كيف تأخذ كل قيمة من number وتحسب قيمتها المربعة.
number = 1
while number <= 5:
print(number, 'squared is', number**2)
number = number + 1
1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
5 squared is 25
يمكنك استخدام أي اسم متغير، لكنني اخترت number لأنه منطقي في السياق. خيار عام شائع سيكون ببساطة i. ستستمر الحلقة حتى يصبح number (الذي تم تهيئته بـ 1) أقل من أو يساوي 5. لاحظ أنه بعد أمر print()، يتم زيادة المتغير number بمقدار 1 لأخذ القيمة التالية. إذا لم تقم بالزيادة، فستحصل على حلقة لا نهائية (infinite loop) لأن number لن يصل أبدًا إلى قيمة أكبر من 5. هذا تفصيل مهم جدًا!
كتلة else
عندما يُرجع الشرط False، سيتم استدعاء كتلة else.
number = 1
while number <= 5:
print(number, 'squared is', number**2)
number = number + 1
else:
print('No numbers left!')
1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
5 squared is 25
No numbers left!
لاحظ أن العبارة 'No numbers left!' تُطبع بعد انتهاء الحلقة، أي بعد أن يتم تقييم الشرط number <= 5 إلى False.
كيفية الخروج من حلقة while في بايثون
ببساطة استخدم الكلمة المفتاحية break، وستتوقف الحلقة عن التنفيذ.
number = 1
while number <= 5:
print(number, 'squared is', number**2)
number = number + 1
if number == 4:
break
1 squared is 1
2 squared is 4
3 squared is 9
تعمل الحلقة بشكل طبيعي، وعندما يصل number إلى 4، يتم تقييم عبارة if إلى True ويتم استدعاء الأمر break. هذا ينهي الحلقة قبل حساب القيمة المربعة للأرقام 4 و 5.
كيفية تخطي عنصر في حلقة while
ستقوم الكلمة المفتاحية continue بذلك نيابة عنك. اضطررت إلى عكس ترتيب عبارة if و print() لإظهار كيفية عملها بشكل صحيح.
number = 0
while number < 5:
number = number + 1
if number == 4:
continue
print(number, 'squared is', number**2)
1 squared is 1
2 squared is 4
3 squared is 9
5 squared is 25
يتحقق البرنامج دائمًا مما إذا كانت 4 هي القيمة الحالية لـ number. إذا كانت كذلك، فلن يتم حساب مربع 4 وستتخطى continue إلى التكرار التالي عندما تكون قيمة number هي 5.
حلقات التكرار for
تشبه حلقات for حلقات while بمعنى أنها تستخدم لتكرار كتل من الكود. الفرق الأكثر أهمية هو أنه يمكنك التكرار بسهولة عبر الأنواع المتسلسلة (sequential types).
البنية الأساسية (Basic Syntax)
البنية الأساسية لحلقة for هي كما يلي.
for item in collection:
statement
التكرار عبر قائمة (Loop over a list)
للتكرار عبر قائمة أو أي مجموعة أخرى، ما عليك سوى المتابعة كما هو موضح في المثال أدناه.
cars = ['BMW', 'Ferrari', 'McLaren']
for car in cars:
print(car)
BMW
Ferrari
McLaren
تحتوي قائمة cars على ثلاثة عناصر. ستتكرر حلقة for عبر القائمة وتخزن كل عنصر في المتغير car، ثم تنفذ عبارة، في هذه الحالة print(car)، لطباعة كل سيارة في وحدة التحكم.
دالة range()
تُستخدم دالة range على نطاق واسع في حلقات for لأنها تمنحك طريقة بسيطة لسرد الأرقام. سيتكرر هذا الكود عبر الأرقام من 0 إلى 5 ويطبع كل منها.
for number in range(5):
print(number)
0
1
2
3
4
على النقيض، بدون دالة range()، سنفعل شيئًا كهذا.
numbers = [0, 1, 2, 3, 4]
for number in numbers:
print(number)
0
1
2
3
4
يمكنك أيضًا تحديد start و stop باستخدام range(). هنا نبدأ من 5 ونتوقف عند 10. الرقم الذي تحدده للتوقف لا يتم تضمينه.
for number in range(5, 10):
print(number)
5
6
7
8
9
أخيرًا، من الممكن أيضًا تعيين خطوة (step). هنا نبدأ من 10 ونزيد بمقدار 2 حتى 20، وبما أن 20 هو stop، فإنه لا يتم تضمينه.
for number in range(10, 20, 2):
print(number)
10
12
14
16
18
كتلة else
عندما تنتهي العناصر في القائمة، سيتم استدعاء كتلة else.
cars = ['BMW', 'Ferrari', 'McLaren']
for car in cars:
print(car)
else:
print('No cars left!')
BMW
Ferrari
McLaren
No cars left!
كيفية الخروج من حلقة for في بايثون
ببساطة استخدم الكلمة المفتاحية break، وستتوقف الحلقة عن التنفيذ.
cars = ['BMW', 'Ferrari', 'McLaren']
for car in cars:
print(car)
if car == 'Ferrari':
break
BMW
Ferrari
ستتكرر الحلقة عبر القائمة وتطبع كل سيارة. في هذه الحالة، بعد أن تصل الحلقة إلى 'Ferrari'، يتم استدعاء break ولن يتم طباعة 'McLaren'.
كيفية تخطي عنصر في حلقة for
في هذا القسم، سنتعلم كيف يمكن لـ continue أن تفعل ذلك نيابة عنك. اضطررت إلى عكس ترتيب عبارة if و continue لإظهار كيفية عملها بشكل صحيح. لاحظ أنني أتحقق دائمًا مما إذا كانت 'Ferrari' هي العنصر الحالي. إذا كانت كذلك، فلن تُطبع 'Ferrari'، وستتخطى continue إلى العنصر التالي 'McLaren'.
cars = ['BMW', 'Ferrari', 'McLaren']
for car in cars:
if car == 'Ferrari':
continue
print(car)
BMW
McLaren
التكرار المتداخل: حلقات for متداخلة
أحيانًا يكون لديك مجموعات أكثر تعقيدًا، مثل قائمة من القوائم. للتكرار عبر هذه القوائم، تحتاج إلى حلقات for متداخلة. في هذه الحالة، لدي ثلاث قوائم: واحدة لطرازات BMW، وأخرى لطرازات Ferrari، وأخيرًا واحدة لطرازات McLaren. ستتكرر الحلقة الأولى عبر قائمة كل علامة تجارية، وستتكرر الثانية عبر طرازات كل علامة تجارية.
car_models = [
['BMW I8', 'BMW X3', 'BMW X1'],
['Ferrari 812', 'Ferrari F8', 'Ferrari GTC4'],
['McLaren 570S', 'McLaren 570GT', 'McLaren 720S']
]
for brand in car_models:
for model in brand:
print(model)
BMW I8
BMW X3
BMW X1
Ferrari 812
Ferrari F8
Ferrari GTC4
McLaren 570S
McLaren 570GT
McLaren 720S
التكرار عبر هياكل البيانات الأخرى
يمكن تمديد نفس المنطق الذي يطبق حلقات for على القائمة (list) ليشمل هياكل البيانات الأخرى: المجموعة الثابتة (tuple)، المجموعة (set)، والقاموس (dictionary). سأوضح بإيجاز كيفية إنشاء حلقة أساسية عبر كل منها.
التكرار عبر مجموعة ثابتة (Loop over a Tuple)
people = ('Bob', 'Mary')
for person in people:
print(person)
Bob
Mary
التكرار عبر مجموعة (Loop over a Set)
people = {'Bob', 'Mary'}
for person in people:
print(person)
Bob
Mary
التكرار عبر قاموس (Loop over a Dictionary)
لطباعة المفاتيح:
people = {'Bob': 30, 'Mary': 25}
for person in people:
print(person)
Bob
Mary
لطباعة القيم:
people = {'Bob': 30, 'Mary': 25}
for person in people:
print(people[person])
30
25
الدوال (Functions)
مع نمو الكود، يزداد التعقيد أيضًا. تساعد الدوال (functions) في تنظيم الكود. الدوال هي طريقة مفيدة لإنشاء كتل من الكود يمكنك إعادة استخدامها.
التعريف والاستدعاء (Definition and Calling)
في بايثون، استخدم الكلمة المفتاحية def لتعريف دالة. امنحها اسمًا واستخدم الأقواس لإبلاغ بـ 0 أو أكثر من الوسائط. في السطر بعد بدء التعريف، تذكر أن تقوم بالمسافة البادئة لكتلة الكود. إليك مثال لدالة تسمى print_first_function() تطبع فقط عبارة 'My first function!'. لاستدعاء الدالة، ما عليك سوى استخدام اسمها كما هو محدد.
def print_first_function():
print('My first function!')
print_first_function()
My first function!
إرجاع قيمة (return a value)
استخدم الكلمة المفتاحية return لإرجاع قيمة من الدالة. في هذا المثال، تُرجع الدالة second_function() السلسلة النصية 'My second function!'. لاحظ أن print() هي دالة مدمجة ويتم استدعاء دالتنا من داخلها. يتم تمرير السلسلة النصية التي تُرجعها second_function() كوسيط لدالة print().
def second_function():
return 'My second function!'
print(second_function())
My second function!
إرجاع قيم متعددة (return multiple values)
يمكن للدوال أيضًا إرجاع قيم متعددة في وقت واحد. تُرجع return_numbers() قيمتين في نفس الوقت.
def return_numbers():
return 10, 2
print(return_numbers())
(10, 2)
الوسائط (Arguments)
يمكنك تعريف المعاملات (parameters) بين الأقواس. عند استدعاء دالة بمعاملات، يجب عليك تمرير الوسائط (arguments) وفقًا للمعاملات المحددة. الأمثلة السابقة لم يكن بها معاملات، لذلك لم تكن هناك حاجة لوسائط. ظلت الأقواس فارغة عند استدعاء الدوال.
وسيط واحد (One Argument)
لتحديد معامل واحد، ما عليك سوى تعريفه داخل الأقواس. في هذا المثال، تتوقع الدالة my_number رقمًا واحدًا كوسيط محدد بواسطة المعامل num. ثم يمكن الوصول إلى قيمة الوسيط داخل الدالة لاستخدامها.
def my_number(num):
return 'My number is: ' + str(num)
print(my_number(10))
My number is: 10
وسيطان أو أكثر (Two or more Arguments)
لتحديد المزيد من المعاملات، ما عليك سوى استخدام فاصلة للفصل بينها. هنا لدينا دالة تجمع رقمين تسمى add. تتوقع وسيطين محددين بواسطة first_num و second_num. يتم جمع الوسيطين بواسطة المعامل + ثم تُرجع النتيجة بواسطة return.
def add(first_num, second_num):
return first_num + second_num
print(add(10, 2))
12
هذا المثال مشابه جدًا للمثال الأخير. الفرق الوحيد هو أن لدينا 3 معاملات بدلاً من 2.
def add(first_num, second_num, third_num):
return first_num + second_num + third_num
print(add(10, 2, 3))
15
منطق تعريف المعاملات وتمرير الوسائط هذا هو نفسه لأي عدد من المعاملات. من المهم الإشارة إلى أنه يجب تمرير الوسائط بنفس الترتيب الذي تم تعريف المعاملات به.
قيمة افتراضية (Default value)
يمكنك تعيين قيمة افتراضية لمعامل إذا لم يتم إعطاء أي وسيط باستخدام المعامل = وقيمة من اختيارك. في هذه الدالة، إذا لم يتم إعطاء أي وسيط، يُفترض الرقم 30 كقيمة متوقعة افتراضيًا.
def my_number(my_number = 30):
return 'My number is: ' + str(my_number)
print(my_number(10))
print(my_number())
My number is: 10
My number is: 30
الوسائط الكلمة المفتاحية أو المسماة (Keyword or Named Arguments)
عند استدعاء دالة، يجب أن يتطابق ترتيب الوسائط مع ترتيب المعاملات. البديل هو استخدام الوسائط الكلمة المفتاحية أو المسماة. قم بتعيين الوسائط لمعاملاتها المعنية مباشرة باستخدام اسم المعاملات والمعاملات =. يقوم هذا المثال بقلب الوسائط، لكن الدالة تعمل كما هو متوقع لأنني أخبرها بأي قيمة تذهب إلى أي معامل بالاسم.
def my_numbers(first_number, second_number):
return 'The numbers are: ' + str(first_number) + ' and ' + str(second_number)
print(my_numbers(second_number=30, first_number=10))
The numbers are: 10 and 30
أي عدد من الوسائط: *args
إذا كنت لا ترغب في تحديد عدد المعاملات، فما عليك سوى استخدام * قبل اسم المعامل. ثم ستأخذ الدالة أكبر عدد ممكن من الوسائط حسب الضرورة. يمكن أن يكون اسم المعامل أي شيء مثل *numbers، ولكن هناك اتفاقية في بايثون لاستخدام *args لهذا التعريف لعدد متغير من الوسائط.
def my_numbers(*args):
for arg in args:
print(arg)
my_numbers(10, 2, 3)
10
2
3
أي عدد من الوسائط المسماة: **kwargs
على غرار *args، يمكننا استخدام **kwargs لتمرير أي عدد من الوسائط الكلمة المفتاحية التي نريدها، طالما أننا نستخدم **. مرة أخرى، يمكن أن يكون الاسم أي شيء مثل **numbers، ولكن **kwargs هي اتفاقية.
def my_numbers(**kwargs):
for key, value in kwargs.items():
print(key)
print(value)
my_numbers(first_number=30, second_number=10)
first_number
30
second_number
10
أنواع أخرى كوسائط
استخدمت الأمثلة السابقة بشكل أساسي الأرقام، ولكن يمكنك تمرير أي نوع كوسيط وسيتم التعامل معه على هذا النحو داخل الدالة. يأخذ هذا المثال سلاسل نصية كوسائط.
def my_sport(sport):
print('I like ' + sport)
my_sport('football')
my_sport('swimming')
I like football
I like swimming
تأخذ هذه الدالة قائمة كوسيط.
def my_numbers(numbers):
for number in numbers:
print(number)
my_numbers([30, 10, 64, 92, 105])
30
10
64
92
105
نطاق المتغيرات (Scope)
المكان الذي يتم فيه إنشاء المتغير يحدد مدى توفره للوصول إليه ومعالجته بواسطة بقية الكود. يُعرف هذا بالنطاق (scope). هناك نوعان من النطاقات: المحلي (local) والعام (global).
النطاق العام (Global Scope)
يسمح لك النطاق العام باستخدام المتغير في أي مكان في برنامجك. إذا كان المتغير الخاص بك خارج دالة، فله نطاق عام افتراضيًا.
name = 'Bob'
def print_name():
print('My name is ' + name)
print_name()
My name is Bob
لاحظ أن الدالة يمكنها استخدام المتغير name وطباعة 'My name is Bob'.
النطاق المحلي (Local Scope)
عندما تعلن عن متغير داخل دالة، فإنه موجود فقط داخل تلك الدالة ولا يمكن الوصول إليه من الخارج.
def print_name():
name = "Bob"
print('My name is ' + name)
print_name()
My name is Bob
تم الإعلان عن المتغير name داخل الدالة، لذا فإن الناتج هو نفسه كما كان من قبل. لكن هذا سيطلق خطأ:
def print_name():
name = 'Bob'
print('My name is ' + name)
print(name)
ناتج الكود أعلاه هو:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'name' is not defined
حاولت طباعة المتغير name من خارج الدالة، لكن نطاق المتغير كان محليًا ولم يتم العثور عليه في نطاق عام.
خلط النطاقات (Mixing Scopes)
إذا استخدمت نفس الاسم للمتغيرات داخل وخارج الدالة، فستستخدم الدالة المتغير الموجود داخل نطاقها. لذا عند استدعاء print_name()، يتم استخدام name='Bob' لطباعة العبارة. من ناحية أخرى، عند استدعاء print() خارج نطاق الدالة، يتم استخدام name="Sarah" بسبب نطاقها العام.
name = "Sarah"
def print_name():
name = 'Bob'
print('My name is ' + name)
print_name()
print(name)
ناتج الكود أعلاه هو:
My name is Bob
Sarah
فهم القوائم (List Comprehensions)
أحيانًا نرغب في إجراء بعض العمليات البسيطة جدًا على عناصر القائمة. يوفر لنا فهم القوائم طريقة موجزة للعمل على القوائم كبديل لطرق التكرار الأخرى، مثل حلقات for.
البنية الأساسية (Basic Syntax)
لاستخدام فهم القائمة لاستبدال حلقة for عادية، يمكننا أن نفعل:
[expression for item in list]
وهو نفس القيام بـ:
for item in list:
expression
إذا أردنا تطبيق تعبير شرطي، فلدينا:
[expression for item in list if conditional]
وهو نفس القيام بـ:
for item in list:
if conditional:
expression
مثال 1: حساب مكعب رقم
الطريقة العادية (Regular way)
numbers = [1, 2, 3, 4, 5]
new_list = []
for n in numbers:
new_list.append(n**3)
print(new_list)
[1, 8, 27, 64, 125]
باستخدام فهم القوائم (Using list comprehensions)
numbers = [1, 2, 3, 4, 5]
new_list = []
new_list = [n**3 for n in numbers]
print(new_list)
[1, 8, 27, 64, 125]
مثال 2: حساب مكعب رقم فقط إذا كان أكبر من 3
باستخدام الشرط، يمكننا تصفية القيم التي نريد تطبيق التعبير عليها فقط.
الطريقة العادية (Regular way)
numbers = [1, 2, 3, 4, 5]
new_list = []
for n in numbers:
if (n > 3):
new_list.append(n**3)
print(new_list)
[64, 125]
باستخدام فهم القوائم (Using list comprehensions)
numbers = [1, 2, 3, 4, 5]
new_list = []
new_list = [n**3 for n in numbers if n > 3]
print(new_list)
[64, 125]
مثال 3: استدعاء الدوال باستخدام فهم القوائم
يمكننا أيضًا استدعاء الدوال باستخدام بنية فهم القوائم:
numbers = [1, 2, 3, 4, 5]
new_list = []
def cube(number):
return number**3
new_list = [cube(n) for n in numbers if n > 3]
print(new_list)
[64, 125]
دوال لامدا (Lambda Functions)
يمكن لدالة لامدا (lambda function) في بايثون أن تحتوي على تعبير واحد فقط ولا يمكن أن تحتوي على أسطر متعددة. من المفترض أن تجعل إنشاء بعض المنطق الصغير في سطر واحد أسهل بدلاً من دالة كاملة كما هو معتاد. دوال لامدا هي أيضًا مجهولة (anonymous)، مما يعني أنه لا توجد حاجة لتسميتها.
البنية الأساسية (Basic Syntax)
البنية الأساسية بسيطة جدًا: ما عليك سوى استخدام الكلمة المفتاحية lambda، وتحديد المعاملات المطلوبة، واستخدام : للفصل بين المعاملات والتعبير. الشكل العام هو:
lambda arguments : expression
مثال بمعامل واحد
انظر إلى هذا المثال باستخدام معامل واحد فقط:
cubic = lambda number : number**3
print(cubic(2))
8
مثال بمعاملات متعددة
إذا أردت، يمكنك أيضًا أن يكون لديك معاملات متعددة.
exponential = lambda multiplier, number, exponent : multiplier * number**exponent
print(exponential(2, 2, 3))
16
استدعاء دالة لامدا مباشرة
لا تحتاج إلى استخدام متغير كما فعلنا من قبل. بدلاً من ذلك، يمكنك استخدام الأقواس حول دالة لامدا وزوج آخر من الأقواس حول الوسائط. سيتم الإعلان عن الدالة وتنفيذها في نفس السطر.
(lambda multiplier, number, exponent : multiplier * number**exponent)(2, 2, 3)
16
أمثلة باستخدام دوال لامدا مع دوال مدمجة أخرى
دالة Map
تطبق دالة Map التعبير على كل عنصر في القائمة. دعنا نحسب مكعب كل رقم في القائمة.
numbers = [2, 5, 10]
cubics = list(map(lambda number : number**3, numbers))
print(cubics)
[8, 125, 1000]
دالة Filter
ستقوم دالة Filter بتصفية القائمة بناءً على التعبير. دعنا نصفي للحصول على الأرقام الأكبر من 5 فقط.
numbers = [2, 5, 10]
filtered_list = list(filter(lambda number : number > 5, numbers))
print(filtered_list)
[10]
الوحدات البرمجية (Modules)
بعد فترة، يبدأ الكود الخاص بك في أن يصبح أكثر تعقيدًا مع الكثير من الدوال والمتغيرات. لتسهيل تنظيم الكود، نستخدم الوحدات البرمجية (Modules). تتمتع الوحدة المصممة جيدًا أيضًا بميزة كونها قابلة لإعادة الاستخدام، لذا تكتب الكود مرة واحدة وتعيد استخدامه في كل مكان. يمكنك كتابة وحدة تحتوي على جميع العمليات الرياضية ويمكن للآخرين استخدامها. وإذا احتجت، يمكنك استخدام وحدات الآخرين لتبسيط الكود الخاص بك، مما يسرع مشروعك. في لغات البرمجة الأخرى، يُشار إليها أيضًا بالمكتبات (libraries).
استخدام وحدة برمجية
لاستخدام وحدة برمجية، نستخدم الكلمة المفتاحية import. كما يوحي الاسم، يجب أن نخبر برنامجنا بالوحدة التي يجب استيرادها. بعد ذلك، يمكننا استخدام أي دالة متاحة في تلك الوحدة. دعنا نرى مثالًا باستخدام وحدة math. أولاً، دعنا نرى كيفية الوصول إلى ثابت، وهو عدد أويلر (Euler's number).
import math
math.e
2.718281828459045
في هذا المثال الثاني، سنستخدم دالة تحسب الجذر التربيعي لعدد. من الممكن أيضًا استخدام الكلمة المفتاحية as لإنشاء اسم مستعار (alias).
import math as m
m.sqrt(121)
m.sqrt(729)
11.0
27.0
أخيرًا، باستخدام الكلمة المفتاحية from، يمكننا تحديد ما يجب استيراده بالضبط بدلاً من الوحدة بأكملها واستخدام الدالة مباشرة دون اسم الوحدة. يستخدم هذا المثال دالة floor() التي تُرجع أكبر عدد صحيح أقل من أو يساوي عددًا معينًا.
from math import floor
floor(9.8923)
9
إنشاء وحدة برمجية
الآن بعد أن عرفنا كيفية استخدام الوحدات، دعنا نرى كيفية إنشاء واحدة. ستكون وحدة تحتوي على العمليات الرياضية الأساسية add، subtract، multiply، divide وسيتم تسميتها basic_operations. أنشئ ملف basic_operations.py بالدوال الأربع.
def add(first_num, second_num):
return first_num + second_num
def subtract(first_num, second_num):
return first_num - second_num
def multiply(first_num, second_num):
return first_num * second_num
def divide(first_num, second_num):
return first_num / second_num
ثم، ما عليك سوى استيراد وحدة basic_operations واستخدام الدوال.
import basic_operations
basic_operations.add(10, 2)
basic_operations.subtract(10, 2)
basic_operations.multiply(10, 2)
basic_operations.divide(10, 2)
12
8
20
5.0
فهم if __name__ == '__main__'
أنت في طور بناء وحدة تحتوي على العمليات الرياضية الأساسية add، subtract، multiply، و divide تسمى basic_operations محفوظة في ملف basic_operations.py. لضمان أن كل شيء على ما يرام، يمكنك تشغيل بعض الاختبارات.
def add(first_num, second_num):
return first_num + second_num
def subtract(first_num, second_num):
return first_num - second_num
def multiply(first_num, second_num):
return first_num * second_num
def divide(first_num, second_num):
return first_num / second_num
print(add(10, 2))
print(subtract(10, 2))
print(multiply(10, 2))
print(divide(10, 2))
بعد تشغيل الكود:
renan@pro-home:~$ python3 basic_operations.py
الناتج هو:
12
8
20
5.0
كان الناتج لتلك الاختبارات هو ما توقعناه. الكود الخاص بنا صحيح وجاهز للمشاركة. دعنا نستورد الوحدة الجديدة ونشغلها في وحدة تحكم بايثون.
Python 3.6.9 (default, Nov 7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import basic_operations
12
8
20
5.0
>>>
عند استيراد الوحدة، تُعرض اختباراتنا على الشاشة على الرغم من أننا لم نفعل شيئًا سوى استيراد basic_operations. لإصلاح ذلك، نستخدم if __name__ == '__main__' في ملف basic_operations.py على النحو التالي:
def add(first_num, second_num):
return first_num + second_num
def subtract(first_num, second_num):
return first_num - second_num
def multiply(first_num, second_num):
return first_num * second_num
def divide(first_num, second_num):
return first_num / second_num
if __name__ == '__main__':
print(add(10, 2))
print(subtract(10, 2))
print(multiply(10, 2))
print(divide(10, 2))
سيستمر تشغيل الكود مباشرة في الطرفية في عرض الاختبارات. ولكن عند استيراده كوحدة، لن تظهر الاختبارات ويمكنك استخدام الدوال بالطريقة التي قصدتها.
Python 3.6.9 (default, Nov 7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import basic_operations
>>> basic_operations.multiply(10, 2)
20
>>>
الآن بعد أن عرفت كيفية استخدام if __name__ == '__main__'، دعنا نفهم كيف يعمل. يخبر الشرط متى يتعامل المفسر مع الكود كوحدة أو كبرنامج يتم تنفيذه مباشرة. تحتوي بايثون على هذا المتغير الأصلي المسمى __name__. يمثل هذا المتغير اسم الوحدة وهو اسم ملف .py. أنشئ ملفًا my_program.py بالمحتوى التالي وقم بتنفيذه.
print(__name__)
الناتج سيكون:
__main__
هذا يخبرنا أنه عندما يتم تنفيذ برنامج مباشرة، يتم تعريف المتغير __name__ على أنه __main__. ولكن عند استيراده كوحدة، تكون قيمة __name__ هي اسم الوحدة.
Python 3.6.9 (default, Nov 7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import my_program
my_program
>>>
هذه هي الطريقة التي يميز بها مفسر بايثون سلوك الوحدة المستوردة والبرنامج الذي يتم تنفيذه مباشرة في الطرفية.
التعامل مع الملفات (Files)
يُعد إنشاء الملفات وحذفها وقراءتها والعديد من الدوال الأخرى المطبقة عليها جزءًا لا يتجزأ من العديد من البرامج. على هذا النحو، من المهم جدًا معرفة كيفية تنظيم الملفات والتعامل معها مباشرة من الكود الخاص بك. دعنا نرى كيفية التعامل مع الملفات في بايثون.
إنشاء ملف (File create)
أولاً وقبل كل شيء، الإنشاء! سنستخدم دالة open(). تفتح هذه الدالة ملفًا وتُرجع الكائن المقابل له. الوسيط الأول هو اسم الملف الذي نتعامل معه، والثاني يشير إلى العملية التي نستخدمها. ينشئ الكود أدناه الملف "people.txt"، ويُستخدم الوسيط x عندما نريد فقط إنشاء الملف. إذا كان ملف بنفس الاسم موجودًا بالفعل، فسوف يطلق استثناء (exception).
people_file = open("people.txt", "x")
يمكنك أيضًا استخدام وضع w لإنشاء ملف. على عكس وضع x، لن يطلق استثناء لأن هذا الوضع يشير إلى وضع الكتابة. نحن نفتح ملفًا لكتابة البيانات فيه، وإذا لم يكن الملف موجودًا، يتم إنشاؤه.
people_file = open("people.txt", "w")
الوضع الأخير هو وضع a الذي يرمز إلى الإلحاق (append). كما يوحي الاسم، يمكنك إلحاق المزيد من البيانات بالملف، بينما يقوم وضع w ببساطة بالكتابة فوق أي بيانات موجودة. عند الإلحاق، إذا لم يكن الملف موجودًا، فإنه ينشئه أيضًا.
people_file = open("people.txt", "a")
الكتابة في ملف (File write)
لكتابة البيانات في ملف، ما عليك سوى فتح ملف بوضع w. ثم، لإضافة البيانات، تستخدم الكائن الذي تُرجعه دالة open(). في هذه الحالة، يسمى الكائن people_file. ثم تستدعي دالة write() وتمرر البيانات كوسيط.
people_file = open("people.txt", "w")
people_file.write("Bob\n")
people_file.write("Mary\n")
people_file.write("Sarah\n")
people_file.close()
نستخدم \n في النهاية لكسر السطر، وإلا سيبقى المحتوى في الملف في نفس السطر مثل "BobMarySarah". تفصيل آخر هو إغلاق الملف (close()). هذه ليست مجرد ممارسة جيدة، ولكنها تضمن أيضًا تطبيق تغييراتك على الملف. تذكر أنه عند استخدام وضع w، سيتم الكتابة فوق البيانات التي كانت موجودة بالفعل في الملف بالبيانات الجديدة. لإضافة بيانات جديدة دون فقدان ما كان موجودًا بالفعل، يجب علينا استخدام وضع الإلحاق.
إلحاق البيانات بملف (File append)
يُلحق وضع a بيانات جديدة بالملف، مع الاحتفاظ بالبيانات الموجودة. في هذا المثال، بعد الكتابة الأولى بوضع w، نستخدم وضع a للإلحاق. والنتيجة هي أن كل اسم سيظهر مرتين في الملف "people.txt".
#first write
people_file = open("people.txt", "w")
people_file.write("Bob\n")
people_file.write("Mary\n")
people_file.write("Sarah\n")
people_file.close()
#appending more data
#keeping the existing data
people_file = open("people.txt", "a")
people_file.write("Bob\n")
people_file.write("Mary\n")
people_file.write("Sarah\n")
people_file.close()
قراءة ملف (File read)
قراءة الملف أيضًا مباشرة جدًا: ما عليك سوى استخدام وضع r على النحو التالي. إذا قرأت ملف "people.txt" الذي تم إنشاؤه في المثال الأخير، يجب أن ترى 6 أسماء في الناتج الخاص بك.
people_file = open("people.txt", "r")
print(people_file.read())
Bob
Mary
Sarah
Bob
Mary
Sarah
تقرأ دالة read() الملف بأكمله دفعة واحدة. إذا استخدمت دالة readline()، يمكنك قراءة الملف سطرًا بسطر.
people_file = open("people.txt", "r")
print(people_file.readline())
print(people_file.readline())
print(people_file.readline())
Bob
Mary
Sarah
يمكنك أيضًا التكرار لقراءة الأسطر مثل المثال أدناه.
people_file = open("people.txt", "r")
for person in people_file:
print(person)
Bob
Mary
Sarah
Bob
Mary
Sarah
حذف ملف (Delete a File)
لحذف ملف، تحتاج أيضًا إلى وحدة os. استخدم دالة remove().
import os
os.remove('my_file.txt')
التحقق مما إذا كان الملف موجودًا (Check if a File Exists)
استخدم دالة os.path.exists() للتحقق من وجود ملف.
import os
if os.path.exists('my_file.txt'):
os.remove('my_file.txt')
else:
print('There is no such file!')
نسخ ملف (Copy a File)
لهذا الغرض، أحب استخدام دالة copyfile() من وحدة shutil.
from shutil import copyfile
copyfile('my_file.txt', 'another_file.txt')
هناك بعض الخيارات لنسخ ملف، ولكن copyfile() هي الأسرع.
إعادة تسمية ونقل ملف (Rename and Move a File)
إذا كنت بحاجة إلى نقل أو إعادة تسمية ملف، يمكنك استخدام دالة move() من وحدة shutil.
from shutil import move
move('my_file.txt', 'another_file.txt')
الفئات والكائنات (Classes and Objects)
الفئات (Classes) والكائنات (Objects) هما المفهومان الأساسيان للبرمجة الموجهة للكائنات (Object-Oriented Programming). في بايثون، كل شيء هو كائن! المتغير (الكائن) هو مجرد نسخة (instance) من نوعه (الفئة). لهذا السبب عندما تتحقق من نوع متغير، يمكنك رؤية الكلمة المفتاحية class بجانب نوعه (الفئة). يوضح مقتطف الكود هذا أن my_city هو كائن وهو نسخة من الفئة str.
my_city = "New York"
print(type(my_city))
<class 'str'>
التمييز بين الفئة والكائن
تمنحك الفئة طريقة قياسية لإنشاء الكائنات. الفئة تشبه مشروعًا أساسيًا. لنفترض أنك مهندس تعمل لدى شركة بوينغ. مهمتك الجديدة هي بناء منتج جديد للشركة، نموذج جديد يسمى 747-Space. هذه الطائرة تحلق على ارتفاعات أعلى من الطرازات التجارية الأخرى. تحتاج بوينغ إلى بناء العشرات من هذه الطائرات لبيعها لشركات الطيران في جميع أنحاء العالم، ويجب أن تكون جميع الطائرات متطابقة. لضمان أن الطائرات (الكائنات) تتبع نفس المعايير، تحتاج إلى مشروع (فئة) يمكن تكراره. الفئة هي مشروع، مخطط لكائن. بهذه الطريقة تقوم بإنشاء المشروع مرة واحدة، وتعيد استخدامه عدة مرات. في مثال الكود الخاص بنا سابقًا، اعتبر أن كل سلسلة نصية لها نفس السلوك ونفس السمات. لذلك من المنطقي أن يكون للسلاسل النصية فئة str لتعريفها.
السمات والدوال (Attributes and Methods)
الكائنات لها بعض السلوك الذي تُحدده السمات (attributes) والدوال (methods). ببساطة، في سياق الكائن، السمات هي متغيرات والدوال هي دوال مرتبطة بكائن. على سبيل المثال، تحتوي السلسلة النصية على العديد من الدوال المدمجة التي يمكننا استخدامها. تعمل مثل الدوال، ما عليك سوى فصلها عن الكائنات باستخدام .. في مقتطف الكود هذا، أنا أستدعي دالة replace() من المتغير النصي my_city وهو كائن، ونسخة من الفئة str. تستبدل دالة replace() جزءًا من السلسلة النصية بآخر وتُرجع سلسلة نصية جديدة بالتغيير. تظل السلسلة النصية الأصلية كما هي. دعنا نستبدل 'New' بـ 'Old' في 'New York'.
my_city = 'New York'
print(my_city.replace('New', 'Old'))
print(my_city)
Old York
New York
إنشاء فئة (Creating a Class)
لقد استخدمنا العديد من الكائنات (نسخ من الفئات) مثل السلاسل النصية والأعداد الصحيحة والقوائم والقواميس. جميعها نسخ من فئات معرفة مسبقًا في بايثون. لإنشاء فئاتنا الخاصة، نستخدم الكلمة المفتاحية class. حسب الاتفاقية، يتطابق اسم الفئة مع اسم ملف .py وبالتالي الوحدة. وهي أيضًا ممارسة جيدة لتنظيم الكود. أنشئ ملفًا vehicle.py بالفئة Vehicle التالية.
class Vehicle:
def __init__(self, year, model, plate_number, current_speed = 0):
self.year = year
self.model = model
self.plate_number = plate_number
self.current_speed = current_speed
def move(self):
self.current_speed += 1
def accelerate(self, value):
self.current_speed += value
def stop(self):
self.current_speed = 0
def vehicle_details(self):
return self.model + ', ' + str(self.year) + ', ' + self.plate_number
دعنا نقسم الفئة لشرحها على أجزاء.
- تُستخدم الكلمة المفتاحية
classلتحديد اسم الفئةVehicle. - دالة
__init__هي دالة مدمجة تمتلكها جميع الفئات. تُستدعى عند إنشاء كائن وتُستخدم غالبًا لتهيئة السمات، وتعيين قيم لها، على غرار ما يتم للمتغيرات. - المعامل الأول
selfفي دالة__init__هو مرجع إلى الكائن (النسخة) نفسه. نسميهselfحسب الاتفاقية ويجب أن يكون المعامل الأول في كل دالة نسخة (instance method)، كما ترى في تعريفات الدوال الأخرىdef move(self)،def accelerate(self, value)،def stop(self)، وdef vehicle_details(self). - تحتوي فئة
Vehicleعلى 5 سمات (بما في ذلكself):year،model،plate_number، وcurrent_speed. داخل__init__، يتم تهيئة كل منها بالمعاملات المعطاة عند إنشاء الكائن. لاحظ أنcurrent_speedيتم تهيئتها بـ0افتراضيًا، مما يعني أنه إذا لم يتم إعطاء قيمة، فستكونcurrent_speedمساوية لـ 0 عند إنشاء الكائن لأول مرة. - أخيرًا، لدينا ثلاث دوال لمعالجة مركبتنا فيما يتعلق بسرعتها:
def move(self)،def accelerate(self, value)، وdef stop(self). ودالة واحدة لإرجاع معلومات حول المركبة:def vehicle_details(self). يعمل التنفيذ داخل الدوال بنفس طريقة عمل الدوال العادية. يمكنك أيضًا أن يكون لديكreturnلإرجاع بعض القيم في نهاية الدالة كما هو موضح بواسطةdef vehicle_details(self).
استخدام الفئة (Using the Class)
لاستخدام الفئة في الطرفية الخاصة بك، قم باستيراد فئة Vehicle من وحدة vehicle. أنشئ نسخة تسمى my_car، مع تهيئة year بـ 2009، و model بـ 'F8'، و plate_number بـ 'ABC1234'، و current_speed بـ 100. لا يؤخذ المعامل self في الاعتبار عند استدعاء الدوال. يستنتج مفسر بايثون قيمته تلقائيًا على أنها الكائن/النسخة الحالية، لذلك ما علينا سوى تمرير الوسائط الأخرى عند إنشاء الكائنات واستدعاء الدوال.
الآن استخدم الدوال لـ move() السيارة التي تزيد من current_speed بمقدار 1، و accelerate(10) التي تزيد من current_speed بالقيمة المعطاة في الوسيط، و stop() التي تعين current_speed إلى 0. تذكر طباعة قيمة current_speed عند كل أمر لرؤية التغييرات. لإنهاء الاختبار، استدعِ vehicle_details() لطباعة المعلومات حول مركبتنا.
>>> from vehicle import Vehicle
>>>
>>> my_car = Vehicle(2009, 'F8', 'ABC1234', 100)
>>> print(my_car.current_speed)
100
>>> my_car.move()
>>> print(my_car.current_speed)
101
>>> my_car.accelerate(10)
>>> print(my_car.current_speed)
111
>>> my_car.stop()
>>> print(my_car.current_speed)
0
>>> print(my_car.vehicle_details())
F8, 2009, ABC1234
إذا لم نقم بتعيين القيمة الأولية لـ current_speed، فستكون صفرًا افتراضيًا كما ذكرنا سابقًا وكما هو موضح في المثال التالي.
>>> from vehicle import Vehicle
>>>
>>> my_car = Vehicle(2009, 'F8', 'ABC1234')
>>> print(my_car.current_speed)
0
>>> my_car.move()
>>> print(my_car.current_speed)
1
>>> my_car.accelerate(10)
>>> print(my_car.current_speed)
11
>>> my_car.stop()
>>> print(my_car.current_speed)
0
>>> print(my_car.vehicle_details())
F8, 2009, ABC1234
الوراثة (Inheritance)
دعنا نحدد فئة Vehicle عامة ونحفظها داخل ملف vehicle.py.
class Vehicle:
def __init__(self, year, model, plate_number, current_speed):
self.year = year
self.model = model
self.plate_number = plate_number
self.current_speed = current_speed
def move(self):
self.current_speed += 1
def accelerate(self, value):
self.current_speed += value
def stop(self):
self.current_speed = 0
def vehicle_details(self):
return self.model + ', ' + str(self.year) + ', ' + self.plate_number
تحتوي المركبة على سمات year، model، plate_number، و current_speed. تعريف المركبة في فئة Vehicle عام جدًا وقد لا يكون مناسبًا للشاحنات، على سبيل المثال، لأنه يجب أن يتضمن سمة cargo. من ناحية أخرى، لا معنى لسمة cargo للمركبات الصغيرة مثل الدراجات النارية. لحل هذه المشكلة، يمكننا استخدام الوراثة (inheritance).
عندما ترث فئة (الابنة) فئة أخرى (الأم)، فإن جميع السمات والدوال من الفئة الأم تُورث بواسطة الفئة الابنة.
الفئة الأم والابنة (Parent and Child)
في حالتنا، نريد أن ترث فئة Truck الجديدة كل شيء من فئة Vehicle. ثم نريدها أن تضيف سمة خاصة بها current_cargo للتحكم في إضافة وإزالة البضائع من الشاحنة. تسمى فئة Truck فئة ابنة ترث من فئتها الأم Vehicle. تسمى الفئة الأم أيضًا الفئة الفائقة (superclass) بينما تسمى الفئة الابنة أيضًا الفئة الفرعية (subclass).
أنشئ فئة Truck واحفظها داخل ملف truck.py.
from vehicle import Vehicle
class Truck(Vehicle):
def __init__(self, year, model, plate_number, current_speed, current_cargo):
super().__init__(year, model, plate_number, current_speed)
self.current_cargo = current_cargo
def add_cargo(self, cargo):
self.current_cargo += cargo
def remove_cargo(self, cargo):
self.current_cargo -= cargo
دعنا نقسم الفئة لشرحها على أجزاء.
- تشير فئة
Vehicleداخل الأقواس عند تعريف فئةTruckإلى أن الفئة الأمVehicleتُورث بواسطة ابنتهاTruck. - تحتوي دالة
__init__علىselfكمعاملها الأول، كالمعتاد. المعاملاتyear،model،plate_number، وcurrent_speedموجودة لتتوافق مع تلك الموجودة في فئةVehicle. أضفنا معاملًا جديدًاcurrent_cargoمناسبًا لفئةTruck. - في السطر الأول من دالة
__init__لفئةTruck، يجب علينا استدعاء دالة__init__لفئةVehicle. للقيام بذلك، نستخدمsuper()لإنشاء مرجع إلى الفئة الفائقةVehicle، لذلك عندما يتم استدعاءsuper().__init__(year, model, plate_number, current_speed)، فإننا نتجنب تكرار الكود الخاص بنا. بعد ذلك، يمكننا تعيين قيمةcurrent_cargoبشكل طبيعي. - أخيرًا، لدينا دالتان للتعامل مع
current_cargo:def add_cargo(self, cargo):، وdef remove_cargo(self, cargo):. - تذكر أن
Truckترث السمات والدوال منVehicle، لذلك لدينا أيضًا وصول ضمني إلى الدوال التي تعالج السرعة:def move(self)،def accelerate(self, value)، وdef stop(self).
استخدام فئة Truck
لاستخدام الفئة في الطرفية الخاصة بك، قم باستيراد فئة Truck من وحدة truck. أنشئ نسخة تسمى my_truck، مع تهيئة year بـ 2015، و model بـ 'V8'، و plate_number بـ 'XYZ1234'، و current_speed بـ 0، و current_cargo بـ 0. استخدم add_cargo(10) لزيادة current_cargo بمقدار 10، و remove_cargo(4) لتقليل current_cargo بمقدار 4. تذكر طباعة قيمة current_cargo عند كل أمر لرؤية التغييرات. عن طريق الوراثة، يمكننا استخدام الدوال من فئة Vehicle لـ move() الشاحنة التي تزيد من current_speed بمقدار 1، و accelerate(10) التي تزيد من current_speed بالقيمة المعطاة في الوسيط، و stop() التي تعين current_speed إلى 0. تذكر طباعة قيمة current_speed عند كل تفاعل لرؤية التغييرات. لإنهاء الاختبار، استدعِ vehicle_details() الموروثة من فئة Vehicle لطباعة المعلومات حول شاحنتنا.
>>> from truck import Truck
>>>
>>> my_truck = Truck(2015, 'V8', 'XYZ1234', 0, 0)
>>> print(my_truck.current_cargo)
0
>>> my_truck.add_cargo(10)
>>> print(my_truck.current_cargo)
10
>>> my_truck.remove_cargo(4)
>>> print(my_truck.current_cargo)
6
>>> print(my_truck.current_speed)
0
>>> my_truck.accelerate(10)
>>> print(my_truck.current_speed)
10
>>> my_truck.stop()
>>> print(my_truck.current_speed)
0
>>> print(my_truck.vehicle_details())
V8, 2015, XYZ1234
الاستثناءات (Exceptions)
الأخطاء جزء من حياة كل مبرمج، ومعرفة كيفية التعامل معها هي مهارة بحد ذاتها. الطريقة التي تتعامل بها بايثون مع الأخطاء تسمى 'معالجة الاستثناءات' (Exception Handling). إذا واجه جزء من الكود خطأ، فسيرفع مفسر بايثون استثناء.
أنواع الاستثناءات (Types of Exceptions)
دعنا نحاول إطلاق بعض الاستثناءات عمدًا ونرى الأخطاء التي تنتجها.
TypeError
أولاً، حاول إضافة سلسلة نصية وعدد صحيح.
'I am a string' + 32
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not int
IndexError
الآن، حاول الوصول إلى فهرس غير موجود في قائمة. خطأ شائع هو نسيان أن التسلسلات مفهرسة من 0، مما يعني أن العنصر الأول له الفهرس 0، وليس 1. في هذا المثال، تنتهي قائمة car_brands عند الفهرس 2.
car_brands = ['ford', 'ferrari', 'bmw']
print(car_brands[3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
NameError
إذا حاولنا طباعة متغير غير موجود:
print(my_variable)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'my_variable' is not defined
ZeroDivisionError
لا تسمح الرياضيات بالقسمة على صفر، لذا فإن محاولة القيام بذلك ستطلق خطأ، كما هو متوقع.
32 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
كانت هذه مجرد عينة من أنواع الاستثناءات التي قد تراها خلال روتينك اليومي وما يمكن أن يسبب كل منها.
معالجة الاستثناءات (Exception Handling)
الآن نعرف كيفية التسبب في أخطاء ستعطل الكود الخاص بنا وتظهر لنا بعض الرسائل التي تقول إن هناك خطأ ما. لمعالجة هذه الاستثناءات، ما عليك سوى استخدام عبارة try/except.
try:
32 / 0
except:
print('Dividing by zero!')
Dividing by zero!
يوضح المثال أعلاه استخدام عبارة try. ضع كتلة الكود التي قد تسبب استثناء داخل نطاق try. إذا سار كل شيء على ما يرام، فلن يتم استدعاء كتلة except. ولكن إذا تم إطلاق استثناء، يتم تنفيذ كتلة الكود داخل except. بهذه الطريقة لا يتعطل البرنامج، وإذا كان لديك بعض الكود بعد الاستثناء، فسيستمر في العمل إذا أردت ذلك.
معالجة استثناءات محددة (Specific Exception Handling)
في المثال الأخير، كانت كتلة except عامة، مما يعني أنها كانت تلتقط أي شيء. الممارسة الجيدة هي تحديد نوع الاستثناء الذي نحاول التقاطه، مما يساعد كثيرًا عند تصحيح الكود لاحقًا. إذا كنت تعلم أن كتلة من الكود يمكن أن تطلق IndexError، فحددها في except:
try:
car_brands = ['ford', 'ferrari', 'bmw']
print(car_brands[3])
except IndexError:
print('There is no such index!')
There is no such index!
يمكنك استخدام مجموعة ثابتة (tuple) لتحديد أي عدد تريده من أنواع الاستثناءات في عبارة except واحدة:
try:
print('My code!')
except (IndexError, ZeroDivisionError, TypeError):
print('My Excepetion!')
كتلة else
من الممكن إضافة أمر else في نهاية عبارة try/except. يتم تشغيله فقط إذا لم تكن هناك استثناءات.
my_variable = 'My variable'
try:
print(my_variable)
except NameError:
print('NameError caught!')
else:
print('No NameError')
My variable
No NameError
إطلاق الاستثناءات (Raising Exceptions)
يسمح لك الأمر raise بإطلاق استثناء يدويًا. هذا مفيد بشكل خاص إذا كنت ترغب في التقاط استثناء والقيام بشيء به - مثل تسجيل الخطأ بطريقة مخصصة مثل إعادة توجيهه إلى مجمع سجلات (log aggregator)، أو إنهاء تنفيذ الكود نظرًا لأن الخطأ لا ينبغي أن يسمح بتقدم البرنامج.
try:
raise IndexError('This index is not allowed')
except:
print('Doing something with the exception!')
raise
Doing something with the exception!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IndexError: This index is not allowed
كتلة finally
يتم تنفيذ كتلة finally بغض النظر عما إذا كانت الاستثناءات قد تم إطلاقها أم لا. عادة ما تكون موجودة للسماح للبرنامج بتنظيف الموارد مثل الملفات والذاكرة واتصالات الشبكة وما إلى ذلك.
try:
print(my_variable)
except NameError:
print('Except block')
finally:
print('Finally block')
Except block
Finally block
الخلاصة التقنية
يُقدم هذا الدليل الشامل للمبتدئين في بايثون رحلة متكاملة عبر أساسيات هذه اللغة البرمجية القوية والمتعددة الاستخدامات. لقد استعرضنا مفاهيم جوهرية بدءًا من بيئة العمل وتثبيت بايثون 3، مرورًا ببنية اللغة، وأنواع البيانات المتنوعة، وصولًا إلى آليات التحكم في التدفق مثل الحلقات والجمل الشرطية. كما تطرقنا إلى تنظيم الكود عبر الدوال والوحدات، ومبادئ البرمجة كائنية التوجه من خلال الفئات والوراثة، وأخيرًا، كيفية التعامل مع الملفات ومعالجة الاستثناءات لإنشاء تطبيقات قوية وموثوقة. إن فهم هذه اللبنات الأساسية يمثل نقطة انطلاق ممتازة لأي مطور طموح يرغب في استكشاف الإمكانيات اللامحدودة لبايثون في مجالات مثل تحليل البيانات وتطوير الويب والذكاء الاصطناعي. تذكر أن الممارسة المستمرة هي مفتاح الإتقان.