البحث في الموقع
المحتوى عن 'function'.
-
دالتا VLOOKUP و HLOOKUP هي إحدى دوال البحث والإشارة Lookup and Reference وهي تُستخدم للبحث عن قيمة محددة في صف أو عمود، ومن ثم إرجاع قيمة معيّنة في الموضع نفسه من الصف أو العمود الثاني. سنتعرّف في هذا الدرس على هاتين الدالتين وكيفية استخدامهما. VLOOKUP اسم هذه الدالة هو اختصار لـ "Vertical Lookup" (البحث العمودي) وهي تُستخدم للبحث في عمود محدد عن قيمة محددة حسب الصفوف، وعند العثور على تلك القيمة تقوم بإرجاع ما يقابلها في العمود الثاني (الذي نقوم بتحديده في الصيغة أيضًا). يمكنك تشبيه عمل هذه الدالة بدليل الهاتف، حيث تقوم بالبحث عن رقم شخص محدد بالبحث عن اسمه أولا في عمود الأسماء، وعندما تجد الاسم المطلوب تعثر على الرقم الذي يقابله في العمود الثاني (عمود الأرقام). البناء العام لصيغة الدالة VLOOKUP (lookup_value; table_array; col_index_num; [range_lookup]) lookup_value: القيمة التي تريد البحث عنها. يجب أن تكون هذه القيمة موجودة في العمود الأول لنطاق الخلايا الذي نحدده في table_array. هذا المُعطى argument وجوده ضروري في الصيغة. table_array: ويمثل نطاق الخلايا الذي يحتوي البيانات التي تبحث فيها الدالة. وهذا المعطى وجوده ضروري أيضًا. col_index_num: رقم العمود في نطاق الخلايا table_array الذي يحتوي على القيمة التي سيتم إرجاعها. وجوده مطلوب في الدالة. range_lookup: هذا المعطى هو عبارة عن قيمة منطقية logical تحدد من خلالها فيما إذا كنت تريد من دالة VLOOKUP البحث عن تطابق تام (بإدخال القيمة FALSE) أو تطابق تقريبي (بإدخال القيمة TRUE) مع قيمة lookup_value، ووجوده اختياري في الصيغة. ملاحظة: عند استخدام القيمة المنطقية TRUE يجب أن يكون العمود الأول في نطاق الخلايا table_array مرتبا تصاعديا لكي يتم إرجاع قيمة صحيحة. هل ترغب في الحصول على مستندات إكسل احترافية؟ وظّف محلل بيانات خبير لتحرير مستنداتك وتنسيقها من مستقل أضف مشروعك الآن مثال 1 الجدول أدناه يحتوي على بيانات الموظفين لشركة ما. عدد صفوف الجدول هو 100 صف تقريبا. في مثل هذه الجداول الكبيرة (وما يفوقها) قد يكون من المضيعة للوقت البحث في كل صف من صفوف الجدول إذا رغبنا في العثور على معلومة معينة. وسيكون الأمر أسهل وأسرع بكثير باستخدام دالة VLOOKUP. المطلوب هنا هو العثور على قسم ومقدار راتب الموظف صاحب البطاقة رقم 100، والموظف صاحب البطاقة رقم 65. نضع المؤشر في الخلية التي نريد إرجاع القيمة الأولى فيها، وهي الخلية H2 في هذا المثال، ثم نذهب إلى تبويب: صيغ Formulas > بحث وإشارة Lookup & Reference > VLOOKUP في مربع الحوار Function Arguments نقوم بتحديد معطيات الدالة: في الحقل الأول، lookup_value، نحدد القيمة التي نريد البحث عنها، وهي رقم البطاقة "100" في هذا المثال، لذلك سنحدد الخلية G2 التي تحتوي هذه القيمة. في الحقل الثاني، table_array، نحدد نطاق الخلايا الذي يحتوي بياناتنا. في هذا المثال سنحدد الجدول بأكمله (A1:D100). في الحقل الثالث، col_index_num، ندخل رقم العمود الذي يحتوي على القيمة التي سيتم إرجاعها، وبما إننا نريد العثور على "قسم" الموظف، فسنقوم بإدخال الرقم "3"، وهو تسلسل عمود "القسم" في الجدول من اليمين إلى اليسار (أي أنّ تسلسل عمود "رقم بطاقة الموظف هو"1"، عمود "تاريخ التوظيف" هو "2"، وهكذا). إذا كان اتجاه الورقة من اليسار إلى اليمين نقوم بحساب رقم العمود من اليسار إلى اليمين. في الحقل الرابع، range_lookup، نقوم بإدخال الرقم صفر (والذي يعني القيمة المنطقية FALSE) لأننا نبحث عن تطابق تام مع الرقم "100"، وليس تطابق تقريبي، بسبب وجود أرقام قريبة من رقم "100" في عمود "رقم بطاقة الموظف". ننقر على OK، وسيتم العثور على قسم صاحب البطاقة رقم 100 فورا، وهو قسم "الخدمات": تفسير عمل الصيغة تقوم الصيغة أولا بالبحث في صفوف عمود "رقم بطاقة الموظف" واحدا تلو الآخر، وعندما تعثر على الرقم "100" تقوم بإيجاد القيمة التي تقابلها في عمود "القسم" ثم ترجع هذه القيمة في الخلية H2. نكرر نفس الخطوات للعثور على مقدار راتب الموظف صاحب البطاقة رقم "100"، وستكون المعطيات كما موضّح في الصورة التالية: قمنا بإدخال الرقم "4" في الحقل الثالث لأنّ تسلسل عمود "الراتب" في الجدول هو الرابع. وكما في الخطوة السابقة، يتم إيجاد النتيجة في الخلية G2: الخطوات نفسها تنطبق على رقم البطاقة "65". مثال 2 الجدول أدناه يحتوي على درجات اختبارين لمجموعة من الطلاب، مع متوسط الدرجات. المطلوب هو إيجاد تقدير كل طالب باستخدام دالة VLOOKUP: بالتأكيد يمكننا إدخال التقديرات يدويا لكل طالب اعتمادًا على قيمة المتوسط، لكن كما ذكرنا، تسّهل دالة VLOOKUP العمل وتختصر الكثير من الوقت. ملاحظة: قمنا بترتيب القيم في عمود "الدرجة" (وهو العمود الأول من نطاق الخلايا table_array) تصاعديا لأننا سنستخدم القيمة المنطقية TRUE في حقل range_lookup. نحدد الخلية التي نريد إرجاع النتيجة فيها، وهي الخلية E2 في هذا المثال، ثم نذهب إلى تبويب: صيغ Formulas > بحث وإشارة Lookup & Reference < VLOOKUP في الحقل الأول نحدد القيمة التي نريد البحث عن التقدير الذي يقابلها، وهي قيمة المتوسط للطالب الأول، 82، في هذا المثال (أي الخلية D2). في الحقل الثاني نحدد نطاق الخلايا الذي سيتم البحث عن التقدير المناسب فيه، وهو النطاق H1:I7. في الحقل الثالث نحدد رقم العمود الذي يحتوي على القيمة التي سيتم إرجاعها. وبما أنّ تسلسل عمود "التقدير" هو الثاني في نطاق الخلايا، سندخل الرقم "2". في الحقل الرابع ندخل الرقم 1 (والذي يعني القيمة المنطقية TRUE) أو نتركه فارغًا، وفي الحالتين سيتم إرجاع نفس النتيجة. السبب في أنّنا اخترنا القيمة TRUE هو أننا نبحث عن تطابق تقريبي مع القيم في عمود "الدرجة" وليس تطابق تام. ننقر على OK وسيتم إرجاع التقدير الذي يقابل قيم المتوسط: تفسير عمل الصيغة ستقوم الصيغة بالبحث عن القيمة "82" أو أقرب أقل قيمة إليها، وعند إيجادها، تقوم بإيجاد ما يقابلها في عمود "التقدير"، ومن ثم إرجاع النتيجة في الخلية E2. نستخدم التعبئة التلقائية لنسخ الصيغة إلى بقية خلايا عمود "التقدير": بعد نسخ الصيغة، نلاحظ حدوث خطأ في إيجاد القيم للخلايا من E7 إلى E23، والسبب هو أنّ البرنامج استخدم نطاق الخلايا H1:I7 كمرجع نسبي relative reference. لذلك سنعيد إدراج الصيغة ونستخدم نطاق الخلايا المذكور كمرجع مطلق absolute reference بوضع مؤشر الكتابة فوق اسم الخلية والنقر على مفتاح F4 (أو بكتابة علامة الدولار قبل وبعد حرف العمود يدويا من لوحة المفاتيح) هذه المرة سيتم إيجاد قيم صحيحة في عمود "التقدير" بأكمله عند استخدام التعبئة التلقائية: أو بدلا من استخدام نطاق الخلايا (H1:I7) كمرجع مطلق وتحديده يدويا كلما أردنا استخدام الدالة، نقوم بتسميته باسم مخصص. وبذلك نستطيع استخدام اسم النطاق في الصيغة. نحدد نطاق الخلايا، ندخل الاسم المرغوب في حقل الاسم (قمنا بتسميته بـ "التقدير")، ثم نضغط Enter: في المرة المقبلة، عندما نقوم بإدراج دالة VLOOKUP (أو أيّة دالة أخرى يُستخدم فيها ذلك النطاق)، نقوم بإدخال اسمه بدلًا من تحديده على الورقة: هذه الطريقة هي أفضل وأكثر كفاءة، وتجعلنا نتلافى الأخطاء التي قد تحدث عند استخدام نوع المرجع غير المناسب. أدخل بياناتك وعالجها بصور وأساليب متعددة بالإكسل استعن بأفضل مقدمي خدمات الإكسل على خمسات اطلب خدمتك الآن HLOOKUP تعمل دالة HLOOKUP (اختصارا لـ Horizontal Lookup) بالضبط كما تعمل دالة VLOOKUP فيما عدا أنّها تقوم بالبحث عن القيم أفقيا وليس عموديا (أي تبحث عن قيمة محددة في صف محدد حسب أعمدة ذلك الصف). البناء العام لصيغة الدالة HLOOKUP(lookup_value; table_array; row_index_num; [range_lookup]) lookup_value: هي القيمة التي تريد البحث عنها. يجب أن تكون هذه القيمة موجودة في الصف الأول لنطاق الخلايا الذي سنحدده في حقل table_array. وهذا المعطى مطلوب في الصيغة. table_array: وهو نطاق الخلايا الذي يحتوي البيانات التي تبحث فيها الدالة. وهذا المعطى مطلوب في الصيغة أيضًا. row_index_num: رقم الصف في نطاق الخلايا table_array الذي يحتوي على القيمة التي سيتم إرجاعها. وجوده مطلوب في الصيغة. range_lookup: هذا المعطى هو عبارة عن قيمة منطقية logical تحدد فيما إذا كنت تريد من دالة HLOOKUP البحث عن تطابق تام (بإدخال القيمة FALSE) أو تطابق تقريبي (بإدخال القيمة TRUE) مع قيمة lookup_value، ووجوده اختياري في الصيغة. ملاحظة: عند استخدام القيمة المنطقية TRUE يجب أن يكون الصف الأول في نطاق الخلايا table_array مرتبا تصاعديا لكي يتم إرجاع قيمة صحيحة. مثال الجدول التالي يحتوي على تواريخ بدء وانتهاء مجموعة من المشاريع. المطلوب هو إيجاد تاريخ انتهاء المشروع رقم 5. بالطبع يمكننا العثور عليه بسهولة في مثل هذا الجدول الصغير، لكن سيصبح الأمر أكثر صعوبة في الجداول الكبير. على كل حال، سنستخدم دالة HLOOKUP للعثور على القيمة المطلوبة. أولا، نحدد الخلية التي نريد إرجاع النتيجة فيها، وهي الخلية B9 في هذا المثال، ثم نذهب إلى تبويب: صيغ Formulas > بحث وإشارة Lookup & Reference < HLOOKUP في مربع الحوار Function Arguments نقوم بتحديد المعطيات: في الحقل الأول، lookup_value، نحدد القيم التي نريد البحث عنها، وهو رقم المشروع "5" في هذا المثال. لذلك سنحدد الخلية B8 التي قمنا بإدخال هذا الرقم فيها مسبقا. في الحقل الثاني، table_array، نحدد نطاق الخلايا الذي سيتم البحث فيه، وهو A1:I13 في هذا المثال. في الحقل الثالث، row_index_num نقوم بإدخال رقم تسلسل الصف الذي يحتوي على النتيجة التي سيتم إرجاعها. وفي هذا المثال هو صف "تاريخ الانتهاء"، تسلسله الثالث (3). في الحقل الرابع، lookup_range نقوم بإدخال الرقم صفر (أي القيمة المنطقية FALSE) لأننا نريد البحث عن قيمة مطابقة تماما للقيمة في حقل lookup_value: ننقر على OK وسيتم إرجاع تاريخ الانتهاء للمشروع رقم 5: تفسير عمل الصيغة ستقوم الصيغة بالبحث في صف "المشروع" عن الرقم 5، وعند العثور عليه ستقوم بإيجاد القيمة المقابلة لهذا الرقم في الصف المحدد في حقل row_index_num، وهو الصف الثالث في مثالنا، ومن ثم إرجاع النتيجة في الخلية B9. يجب أن تأخذ في الاعتبار أنّه إذا كانت قيمة lookup_range تساوي TRUE، ولم تتمكن الدالة من العثور على قيمة lookup_value فستقوم بإرجاع أقرب أقل قيمة من قيمة lookup_value. مثال 2 إذا كنا نريد معرفة تاريخ البداية للمشروع رقم "9" (والذي هو في الحقيقة غير موجود في الجدول) ستكون الصيغة كالتالي: وستكون النتيجة كالتالي: تفسير عمل الصيغة قامت الصيغة بالبحث عن الرقم "9" في صف "المشروع"، وقد تعذّر عليها إيجاده، لذلك قامت بإرجاع "تاريخ البدء" للمشروع رقم "8" وهو أقرب أقل قيمة من الرقم "9". وهذا بسبب أننا قمنا بإدخال القيمة المنطقية TRUE (أي البحث عن تطابق تقريبي). أما إذا قمنا بتحديد القيمة المنطقية FALSE، فستكون النتيجة خطأ #N/A، لأنّ الدالة في هذه الحالة ستبحث عن تطابق تام:
-
إلى الآن، تعرفنا في هذه السلسلة من الدروس على أساسيات التعامل مع أنواع البيانات، المُتغيرات، الجمل الشرطية، وحلقات التكرار for و while. وقد أصبح لديك الآن المعلومات الكافية لبرمجة برامج مُتوسطة قد تحتوي على مئات الأسطر البرمجية، وقد حان الوقت لتتعرف على الدوال لكي تجعل مُهمة إعادة استخدام أجزاء من شيفرتك أكثر سهولة ومرونة، كما ستتعرف على بعض من الدوال المُعرفة مُسبقا في لغة بايثون. للتذكير: جميع الشّيفرات التّي تبدأ بعلامة <<< يجب أن تنفّذ على مفسر بايثون. الدوال الدّالة في البرمجة كاسم المتغيّر يُمكنك استدعاؤها عند الحاجة لكنّ المتغير لا يحمل سوى قيمة واحدة، أمّا الدّالة فتحمل شيفرة مستقلة وقد تكون هذه الشيفرة جملة شرطية أو جملة طباعة أو حلقة تكراريّة أو كل ما سبق. وتُستعمل الدوال أساسا لتجنب تكرار شيفرة عدة مرات، فمثلا لنقل بأنّك كتبت شيفرة للجمع بين عددين ثم بعد ذلك أردت أن تجمع عددين آخرين وهكذا، إذا حاولت تكرار الشيفرة سيكون الأمر مُتعبا جدا خاصة إذا كانت الشيفرة التي تكررها طويلة جدا، لذلك فلغات البرمجة توفر الدوال. لنعتبر بأنّ طباعة جملة "Hello" هي الشيفرة التّي تحملها الدّالة، انظر المثال التّالي: >>> def say_hello(): ... print "Hello" ... >>> say_hello() Hello أولا قمنا بإنشاء الدّالة say_hello في السّطر: def say_hello(): النّقاط الثّلاثة التّي تظهر بعد ذلك السّطر تعني بأن مُفسر بايثون ينتظر مدخلات أخرى، لذلك ندخل شيفرة الطّباعة (تذكر بأن هذه هي الشيفرة الأساسيّة) بعد مساحة بيضاء (أربع مسافات). بعد إنشاء الدّالة سيرجع المفسّر إلى حالته الطّبيعية، بدون أي مُخرجات، وذلك لأنّنا يجب أن نستدعي الدّالة لكي تُنفّذَ الشّيفرة التّي بداخلها، والاستدعاء يكون بكتابة اسم الدّالة مع قوسين: >>> say_hello() ما رأيناه قبل قليل هو كيفية تعريف دالة، كيفية وضع شيفرة داخلها ثم كيفية استدعائها لتنفذ الشيفرة. يُمكن أن نجعل الدالة تُعيد قيمة دون تنفيذ أي شيفرة (رغم أنّها تُنفذ شيفرة الإرجاع)، انظر المثال التالي: >>> def x(): ... return 4 ... >>> x() 4 ما فعلناه هو أنّنا قُمنا بجعل الدالة قيمة عوضا عن أن تُنفذ شيفرة ما، أي أنّنا استخدمنا الدالة x كمُتغير عادي يحمل قيمة مُحدّدة. قد تسأل نفسك، ما فائدة الأمر؟. الأمر مُفيد جدا إذا كان برنامجك كبيرا، بحيث يُمكنك استعمال الدوال كقيمة مُخرجة بعد عدة عمليات. مثلا، إذا كان لديك برنامج يطلب من المُستخدم مُدخلا (كاسمه أو كلمة مروره) وتُريد التحقق من مُدخله وإجراء عمليات عليه، فاستعمال المُتغيرات هنا ليست فكرة جيدة وذلك لأنّ الشيفرة ستكون صعبة التعديل. عوضا عن ذلك يُمكنك أن تقوم بالعمليات على المدخل داخل دالة ثم بعد ذلك تجعل الدالة تحمل القيمة التي ترغب بها في النهاية. دورة تطوير التطبيقات باستخدام لغة Python احترف تطوير التطبيقات مع أكاديمية حسوب والتحق بسوق العمل فور انتهائك من الدورة اشترك الآن ملاحظة حول تسمية الدوال رغم أنك تستطيع تسمية الدوال بأحرف صغيرة وكبيرة معا، من المُفضل تسمية الدالة بأحرف صغيرة والفصل بين كل كلمة والأخرى بمحرف "_". المعاملات Parameters من مُميزات الدوال أنّك تستطيع أن تُعطيها مُعاملات عند تعريفها، وأن تُعطي القيم لهذه المُعاملات إما عند تعريف الدالة (المعاملات الافتراضية) أو لاحقا. لتفهم أكثر، انظر المثال التالي: >>> def say_hello(name): ... print 'Hello', name ... >>> say_hello('Abdelhadi') Hello Abdelhadi >>> say_hello('Hsoub Academy') Hello Hsoub Academy كما ترى لقد قُمنا بتعريف الدالة say_hello مع مُعامل name ووضعنا داخلها جملة طباعة لتطبع Hello متبوعا بقيمة العامل name بعدها قُمنا باستدعاء الدالة وأسندنا للعامل name قيمتين مُختلفتين، وقد كانت النتائج مُختلفة، يُمكنك أن تستدعي نفس الدالة مع معاملات مُختلفة لعدد غير محدود من المرات. يُمكنك كذلك أن تقوم بتعريف دالة مع أكثر من معامل، إليك مثالا على دالة لإعادة مجموع عددين : >>> def add_numbers(n1, n2): ... return n1 + n2 ... >>> add_numbers(3,4) 7 إذا قُمنا بتعريف دالة مع معامل فلا بد أن نقوم بتعيين قيمة العامل عند الاستدعاء وإلا فسيرجع مُفسر Python خطأ كالتّالي: >>> say_hello() TypeError: say_hello() takes exactly 1 argument (0 given) الأمر نفسه يحدث إذا عينت عددا أكثر من العوامل المُفترض، مثلا أن تعطي للدالة say_hello مُعاملين أو أكثر. يُمكنك أن تقوم بوضع قيمة افتراضية لمُعامل في سطر تعريف الدالة: >>> def num(n1, n2 = 10): ... return n1 + n2 ... >>> num(3) 13 يُمكن أن تستعمل هذه الطريقة لعرض خطأ للمُستخدم إذا نسي إدخال المُعاملات. >>> def say_hello(name = '| Error! Check the line that calls the function'): ... print 'Hello', name ... >>> say_hello() Hello | Error! Check the line that calls the function يُمكنك كذلك أن تقوم بعدة عمليات مع الدوال، وإليك قائمة ببعض هذه العمليات: تعريف دالة داخل دالة أخرى بما أن الدوال عبارة عن أجزاء من الشيفرة فتستطيع أن تقوم بإنشاء دالة أخرى أو عدد من الدوال داخل الدالة الواحدة، انظر المثال التالي: >>> def say_hello(name): ... def hello(): ... return 'Hello ' ... print hello() + name ... >>> say_hello('Abdelhadi') Hello Abdelhadi كما ترى أعلاه القيمة Hello ما هي إلا القيمة التي أرجعتها الدالة hello المعرفة بداخل الدالة say_hello. استدعاء دالة داخل دالة أخرى هذا الأمر بسيط، فقط استدع الدالة داخل دالة أخرى وستعمل كلتا الدالتان عند استدعاء الدالة الأم: >>> def say_hello(name): ... print 'Hello', name ... >>> def print_hello(): ... say_hello('Abdelhadi') ... >>> print_hello() Hello Abdelhadi في المثال أعلاه قُمنا باستدعاء الدالة say_hello من داخل الدالة print_hello. إسناد دالة لمتغير تستطيع أن تُنشئ دالة وتقوم بإسنادها لمُتغير بالطّريقة التالية: >>> def say_hello(name): ... print 'Hello', name ... >>> s = say_hello >>>> s('Abdelhadi') Hello Abdelhadi إسناد دالة كمعامل لدالة أخرى قلنا مُسبقا بأنّه يمكن للدالة أن تتصرف كمتغير وذلك عندما نجعلها ترجع قيمة بالجملة return. وهذا يعني بأنّنا نستطيع أن نسند للدالة دالة أخرى. >>> def say_hello(name): ... print 'Hello', name ... >>> def get_name(): ... return 'Abdelhadi' ... >>> say_hello(get_name()) Hello Abdelhadi إرجاع دالة داخل دالة أخرى يُمكنك أيضا أن تستعمل الجملة return لإرجاع دالة داخل دالة أخرى عوضا عن إرجاع قيمة ما، انظر المثال: >>> def get_hello(): ... return 'Hello Abdelhadi' ... >>> def say_hello(): ... return get_hello() ... >>> print say_hello() Hello Abdelhadi ستلاحظ بأنّ الدالة say_hello تحمل قيمة الدالة get_hello، وذلك لأنّنا أرجعنا هذه الأخيرة داخل الدالة say_hello. إسناد عدد لا نهائي من المعاملات لدالة ما لنقل بأنّك تريد أن تقوم بإنشاء دالة تطبع جميع المُحتويات (المُعاملات) التي تُدخلها دون الحاجة إلى تحديد كل معامل على حدة. يُمكنك أن تقوم بالأمر بما يُسمى مُعامل طول المُتغير أو Variable-length argument وذلك كالتالي: >>> def print_arguments(*args): ... print args ... >>> print_arguments(2, 4, 8, 'Abdelhadi', 'Hsoub Academy') (2, 4, 8, 'Abdelhadi', 'Hsoub Academy') المُتغير args عبارة عن صف (Tuple) من القيم، وبالتالي فإنك تستطيع أن تتعامل معه بحلقة For. يُمكن أن تستخدم أي اسم نريده لهذا المعامل، وعموما يعتبر الاسم args* تقليدا بين مُبرمجي بايثون. لاحظ أن الاختلاف بين المعامل العادي والمعامل في المثال أعلاه هو النجمة في البداية. تستطيع أن تجعل المُعاملات قاموسا عوضا عن صف بحيث تُرجع الدالة القاموس الذي يحتوي على اسم المعامل وقيمته، وذلك كالآتي: >>> def print_keyword_args(**kwargs): ... print kwargs ... >>> print_keyword_args(name = 'Abdelhadi', website = 'Hsoub Academy', n = 3) {'website': 'Hsoub Academy', 'name': 'Abdelhadi', 'n': 3} لاحظ بأنّ اسم المُعامل يبدأ بنجمتين هذه المرة، وهذا النوع من المُعاملات يسمى مُعاملات الكلمة المفتاحية Keyword Arguments لأنها ترجع قاموسا مفاتيحه هي أسماء المعاملات التي تختارها أنت وقيم المفاتيح هي قيم المعاملات. المتغيرات المحلية والمتغيرات العامة Local variables and Global variables المتغيرات المحلية هي المتغيرات التي نقوم بإنشائها داخل دالة، أما المتغيرات العامة فهي التي ننشئها خارج الدالة. يُمكنك أن تصل إلى المتغيرات العامة في أي مكان من برنامجك، على خلاف المُتغيرات المحلية التي ستتمكن من الوصول إليها فقط داخل الدالة، انظر المثال التالي: >>> def say_hello(): ... name = 'Abdelhadi' ... print 'Hello', name ... >>> say_hello() Hello Abdelhadi >>> print name Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'name' is not defined قُمنا بتعريف المُتغير name داخل الدالة say_hello وبعدها حاولنا الوصول إليه خارج الدالة، ما أدى إلى خطأ مفاده بأن مُفسر بايثون لم يتعرف على المُتغير. يُمكن أن نجعل المتغير name عامًا بإضافة الكلمة global قبله (عليك أن تقوم بهذا قبل إسناد قيمة للمُتغير)، انظر المثال التالي: >>> def say_hello(): ... global name ... name = 'Abdelhadi' ... >>> say_hello() >>> print name Abdelhadi نُلاحظ بأنّنا استطعنا الوصول إلى المُتغيّر name خارج الدالة التي عُرّفَ بها. تطبيق سنضرب مثالا بالبرنامج الذي أنشأناه في درس التعابير الشرطية والإزاحات. print 'Hello User, this is a basic sign up/login Program' username = raw_input('Enter your username please: ') password = raw_input('Enter the your password please: ') password_verification = raw_input('Verify password: ') if password == password_verification: print 'You have Successfully Signed up! \n' username_sign_in = raw_input('Enter your username please: ') password_sign_in = raw_input('Enter your password please: ') if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' else: print 'The password and the password verification do not match! Please try again' سنركز على شيفرة التحقق من المُستخدم وكلمة المرور: if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' إذا أردنا أن نستخدمها لأكثر من مرة في برنامجنا فعلينا أن نضعها داخل دالة. def user_logged_in?(username_sign_in, username, password_sign_in, password): if username_sign_in == username and password_sign_in == password: return True else: return False يُمكنك استخدام الدالة في أي مكان من الشيفرة: def is_user_logged_in(username_sign_in, username, password_sign_in, password): if username_sign_in == username and password_sign_in == password: return True else: return False new_password = raw_input('Enter new username: ') new_username = raw_input('Enter new password: ') print 'Ok!' password = raw_input('Hello again, Enter your username: ') username = raw_input('Enter username\'s password: ') print is_user_logged_in(username, new_username, password, new_password) الدالة is_user_logged_in تقوم بمُقارنة كلمتي المرور واسمي المُستخدم فإن كانا متطابقين فستصبح قيمة الدالة True أما إن لم تتوافق القيم فإنّ الدالة تحمل القيمة False ويُمكنك الآن استخدام الدالة مع الجمل الشرطية في أي مكان من برنامجك دون الاضطرار لإعادة كتابة شيفرة التحقق كل مرة. كما أنّ التعديل على الشيفرة بسيط جدا، فالتّعديل من مكان واحد (الدالة) يكفي يطبّق على جميع الأماكن الأخرى (أمكنة استدعاء الدالة). الدوال المعرفة مسبقا تُوفر بايثون دوالا مُعرفة مُسبقا، وقد تعاملنا مع كثير منها في الدروس السابقة، وإليك بعض الدوال المُفيدة التي توجد مُسبقا بلغة بايثون. print: دالة الطّباعة التي استخدمناها أكثر من مرة لطباعة القيم في سابق الدروس. Int: دالة تحويل القيم إلى عدد صحيح، مثال: >>> int(5.5) 5 str: دالة تحويل القيم إلى سلسلة نصيّة String: >>> str(True) 'True' وتُستعمل كثيرا لجمع سلسلة نصية بقيمة من نوع آخر بالعامل + (إذا لم تستخدم هذه الدالة فسيعرض لك مُفسر بايثون خطأ يُفيد بأنّك لا تستطيع جمع قيمتين من نوعين مُختلفين): >>> print 'ABC' + str(122) + str(False) ABC122False abs: دالة للحصول على القيمة المُطلقة Absolute Value لعدد ما (إذا كان موجبا فهو العدد نفسه، وإذا كان سالبا فمُقابله): >>> abs(3) 3 >>> abs(-3) 3 len: دالة لقياس عدد عناصر قائمة أو عدد أحرف سلسلة نصية. >>> a = ['Abdelhadi', 'Dyouri', 'Academy', 'Hsoub'] >>> b = 'Hello' >>> len(a) 4 >>> len(b) 5 min: دالة لتحديد أقل قيمة بين قيمتين أو أكثر. >>> min(4, 5, 7, 88, 3, 2) 2 max: دالة لتحديد أقل قيمة بين قيمتين أو أكثر. >>> max(4, 5, 7, 88, 3, 2) 88 range: لتوليد قائمة بأعداد بين قيمة المعامل الأول وقيمة المُعامل الثاني: >>> range(0, 11) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> range(0, 11, 3) [0, 3, 6, 9] raw_input: دالة للحصول على مُدخل نصي من المُستخدم، يُمكنك أن تسند هذا المُدخل إلى مُتغير. >>> def say_hello(name): ... print 'Hello', name ... >>> say_hello(raw_input()) Abdelhadi Hello Abdelhadi كما قُلنا سابقا، فإنك تستطيع أن تقوم بإسناد دالة كمعامل لدالة أخرى، وهذا ما فعلناه في المثال أعلاه، إذ مررنا الدالة raw_input ليكون معاملا للدالة say_hello. تمارين تمرين 1 اكتب برنامجا للحصول على قيمة من المُستخدم وتحويلها إلى قيمة عددية. تمرين 2 اكتب دالة لطباعة جملة لعدد من المرات، واترك للمُستخدم حرية اختيار عدد مرات التكرار (مُساعدة: استعمل الدالة raw_input للحصول على قيمة من المُستخدم) تمرين 3 اكتب دالة للجمع بين عددين يُدخلهما المُستخدم. تمرين 4 بَرمِجْ آلة حاسبة بسيطة تقوم بالجمع، الطّرح، الضرب والقسمة. إليك طريقة العمل: احصل على قيمة العدد الأول من المُستخدم. احصل على قيمة العدد الثاني. حول القيمتين النصيتين إلى قيمتين عدديتين. احصل على العامل الرياضي (*، /، - أو +) من المُستخدم. استخدم الجمل الشرطية لإجراء العملية المُناسبة (إذا كان المُدخل + فقم بالجمع). ترجمة -وبتصرف- من الكتاب Python Practice Book لكاتبه Anand Chitipothu.
-
تخيّل أنك تعيش في قرية لا تتوفّر على شبكة مياه. تحتاج، للحصول على الماء، لأخذ سطل فارغ والذهاب إلى بئر وسط القرية وسحب المياه من البئر ثم العودة إلى المنزل. تعاود الكرة مرات عدّة في اليوم، حسب حاجتك للمياه. سيكون شرحُ ما تفعله بالتفصيل في كل مرة تُسأل فيها عن الأمر مضيعة للوقت؛ لذا بدلا من أن تقول “آخذ سطلا فارغا وأذهب إلى البئر وسط المدينة، ثم أسحب دلوا من الماء من البئر وأفرغه في السطل وأعود”، بدلا من ذلك تجيب اختصارا “أجلب الماء”. لقد أنشأت بهذه الإجابة دالة برمجية Function. تعريف الدوالّ الدالة هي كتلة من الأسطر البرمجية التي تنفّذ مجموعة من المهامّ وفق ترتيب محدَّد، مثلا: “آخذ السطل، أذهب إلى البئر، أسحب الماء منه وأعود”. تُعرَّف الدالة بالصياغة التالية: function functionName (parameters) { // نفّذ المهام هنا } function هي الكلمة المفتاحية التي تخبر جافاسكريبت أنك بصدد الإعلان عن دالة. functionName هو اسمُ الدالة. في المثال أعلاه فإن اسم الدالة يمكن أن يكون drawWater (اغرف الماء). يمكن أن يكون اسمُ الدالة أيا اسم تختاره ما دام يحترم شروط أسماء المتغيّرات، أي: أن يكون كلمة واحدة، أن يتكوّن فقط من حروف لاتينية (a-z, A-Z)، أرقام (0-9) أو علامة تسطير سفلي _. أن لا يكون كلمة محجوزة Reserved keywords في جافاسكريبت. المعاملات Parameters هي مجموعة من المتغيّرات تفصل بينها فاصلة لاتينية , تريد تعريفها للاستخدام داخل الدالة. المعاملات اختيارية ويمكن تعريف دالة دون معاملات. استخدام الدوالّ يمكن استخدامُ الدالة بعد تعريفها. تدلّ العبارات “استخدام الدالة”، “تنفيذ الدالة” أو “استدعاء الدالة” على الشيء ذاته. لاستدعاء الدالة نكتُب اسمَها متبوعا بقوسين (). في ما يلي مثال نعرّف فيه دالة باسم sayHello ثم نستخدمها: // تعريف الدالة function sayHello () { console.log('Hello world!') } // استدعاء الدالة sayHello() ينتُج عن تنفيذ الدالة بالطريقة المشروحة أعلاه طباعةُ العبارة Hello world. الإزاحة The indentation يجب إزاحة جميع الأسطُر البرمجية الموجودة في كتلة، أي تقع بين قوسين معكوفين {}، إلى اليمين. هذه الممارسة مهمّة جدا وتساعد في تسهيل قراءة الشفرة البرمجية وصيانتها، وتمكّنك بنظرة واحدة معرفة أن التعليمة console.log('Hello world') هي جزء من الدالة sayHello: function sayHello () { // تعليمة console.log أدناه مزاحة قليلا إلى اليمين وبالتالي فهي جزء من الدالة sayHello console.log('Hello world!') } يمكنك استخدام مسافتيْن (زر المسافة في لوحة المفاتيح مرتيْن) أو مفتاح الجدولة في لوحة المفاتيح Tab لإزاحة التعليمات في الشفرة. يفضّل بعض المطوّرين مفتاح الجدولة في ما يُفضّل آخرون المسافتين. استخدم أيهما تراه مناسبا، مع التأكد من استخدام نفس طريقة الإزاحة في كامل الشفرة. المعاملات تأخذ معظم الدوال معاملات، وهي عبارة عن سلسلة من المتغيّرات تفصل بينها فاصلة ,، تُعرَّف لتُستخدَم داخل الدالة. يمكنك تعريف معاملات بالعدد الذي تريد. function functionName(param1, param2, param3) { // نفّذ المهام هنا } تُسنَد القيم إلى المعاملات بتمريرها بين قوسين إلى الدالة في سلسلة تفصل بينها فاصلة ,. تُسمَّى القيم المُمرَّرة إلى الدالة بالمعطيات Arguments. يُسنَد المعطى الأول إلى المعامل الأول، والمعطى الثاني إلى المعامل الثاني وهكذا: functionName('arg1', 'arg2') فلنشرح الأمر أكثر بمثال. فلنقل إنك تريد تعريف دالة باسم sayName وظيفتها تسجيل الاسم الشخصي والاسم العائلي لشخص. تبدو الدالة بالشكل التالي: function sayName(firstName, lastName) { console.log('اسمك الشخصي هو ' + firstName) console.log('اسمك العائلي هو ' + lastName) } تُعرّف الدالة معاملين هما firstName وlastName. فلنفترض أن الاسم الشخصي هو “محمد” والاسم العائلي هو “عيسى”. لجعل الدالة تعمل على النحو المرغوب نمرّر لها المعطييْن محمد وعيسى كالتالي: sayName('محمد', 'عيسى') نحصُل بعد تنفيذ الدالة بالطريقة أعلاه على النتيجة التالية: اسمك الشخصي هو محمد اسمك العائلي هو عيسى عند تعريف معامل أثناء تعريف الدالة ثم استخدام الدالة دون تمرير معطيات فإن المعامل سيأخذ القيمة “غير معرَّف” undefined: sayName() النتيجة: // اسمك الشخصي هو undefined // اسمك العائلي هو undefined جملة إرجاع Return statement يمكن أن تحتوي الدوال على جملة إرجاع تتكوَّن من الكلمة المفتاحية return متبوعة بقيمة. function functionName () { return 'some-value' } عندما يجد مفسّر جافاسكريبت هذه الجملة فإنه يتوقّف عن تنفيذ التعليمات الموالية في الدالة ويُرجع قيمة (يمرّر القيمة المعنية إلى الشفرة التي استدعت الدالة): function get2 () { return 2 console.log('blah') // لن تُنفذ هذه التعليمة } const results = get2() console.log(results) // تُطبع القيمة 2، وهي القيمة المُرجَعة من الدالة // ملحوظة: لن تُطبَع القيمة 'blah' إن كانت الكلمة المفتاحية return متبوعة بعبارة بدلا من قيمة حرفية فإن مفسّر جافاسكريبت يحدّد نتيجة تنفيذ العبارة ثم يُرجِع القيمة الناتجة. تذكّر أن القيم التي يمكن لجافاسكريبت تمريرها هي إما أنواع أصلية (مثل سلاسل المحارف، الأعداد والقيم المنطقية) أو كائنات Objects (دوالّ، مصفوفات وكائنات). كلّ ما عدا ذلك يجب تقويمه (معرفة قيمته) قبل التمرير إلى الشفرة التي استُدعِيت فيها الدالة. تسلسل تنفيذ التعليمات عند استدعاء الدوال قد تكون الدوال صعبة الفهم على المبتدئين. سنرى، للتأكد من فهم الدوال تماما، مالذي يحدُث عند تعريف دالة واستدعائها. هذه المرة سنتناول كل خطوة على حدة. في ما يلي الشفرة التي سنعمل على تفكيك عملها: function add2 (num) { return num + 2 } const number = add2(8) console.log(number) // تطبع العدد 10 أولا وقبل كل شيء، نحتاج إلى تعريف الدالة قبل أن نتمكّن من استخدامها. يرى مفسّر جافاسكريبت في السطر الأول الكلمة المفتاحية function فيعرف أن الكلمة التي تليها، أي add2 هي اسم الدالة. بعد تعرّف المفسّر على اسم الدالة يتجاوز الشفرة الموجودة بين معكوفين التي تلي الاسم، لأنه حتى الآن لم يُطلب منه تنفيذ الدالة. في السطر التالي يجد المفسّر أننا عرّفنا متغيّرا ذا قيمة ثابتة اسمه number وأسندنا له القيمة add2(8). بما أن الطرف الموجود على يمين علامة الإسناد = هو دالة، فإن جافاسكريبت سيحتاج إلى تنفيذ الدالة قبل إسناد قيمتها إلى المتغيّر. يعيّن المفسّر القيمة 8 لتكون معطى للمعامل num في الدالة ويبدأ بتنفيذ الدالة. عند الدخول إلى كتلة الدالة (الشفرة بين قوسين معكوفين بعد اسم الدالة) يجد المفسّر أمامه الكلمة المفتاحية return متبوعة بعبارة num + 2، فيعرف أنه سيحتاج إلى معرفة نتيجة العبارة قبل الخروج من الدالة. بما أن قيمة num هي 8 فإن num + 2 يجب أن تساوي 10. عرف المفسّر الآن قيمة العبارة num + 2 ويمكنه بالتالي إرجاع القيمة المُتحصَّل عليها إلى الشفرة التي استدعت الدالة. فيضع القيمة المرجعة مكان الدالة فتُصبح 10 مكان add2(8). يُنشئ المفسّر، بعد اكتمال تنفيذ الطرف الأيمن من عملية إسناد المتغيّر والحصول على نتيجتها، متغيّرا بالاسم المذكور number ويعطيه القيمة 10. هكذا يُقرأ تسلسل تنفيذ التعليمات في الدوال. رفع الدوال Hoisting تُنقَل الدوال تلقائيا عند تعريفها بالطريقة التي رأيناها سابقا إلى أعلى الشفرة البرمجية. بمعنى أن طريقتيْ التعريف والاستخدام التاليّتيْن متكافئتان تماما: function sayHello () { console.log('Hello world!') } sayHello() // تُحوّل الشفرة التالية عند التنفيذ تلقائياإلى الشفرة أعلاه sayHello() function sayHello () { console.log('Hello world!') } قد يؤدّي الرفع التلقائي للدوال إلى الإرباك؛ لذا من المناسب تعريف الدوال دائما قبل استخدامها. تعريف الدوال بعبارات الدوال Function expressions توجد طريقة ثانية لتعريف الدوال، وهي عبارات الدوال. يُعرَّف في هذه الحالة متغيّر ويُسنَد إلى دالة غير مسمّاة (دالة مجهولة الاسم Anonymous funvtion) const sayHello = function () { console.log('This is declared with a function expression!') } ينبغي الانتباه إلى أن الدوال المُعرَّفة بعبارات لا تُنقَل تلقائيا إلى أعلى الشفرة. تُنتج الشفرة التالية خطأ: sayHello () // Error, sayHello is not defined const sayHello = function () { console.log('this is a function!') } تُستخدَم الدوال المُعرَّفة بعبارات كثيرا في توابع الكائنات Object methods وفي الدوالّ السهمية Arrow functions. خاتمة الدالة هي كتلة من التعليمات البرمجية تنفَّذ وفق ترتيب محدَّد على منوال: خذ سطلا فارغا، اذهب إلى البئر، اسحب الماء ثم عُد إلى المنزل. تُستدعى الدالة بإضافة قوسين () بعد اسمها. يمكنك عند استدعاء الدالة إضافة معطيات جديدة بذكرها بين القوسين مفصولة بفاصلة ,. يمكن لكلّ دالة أن تحوي جملة إرجاع تعيد قيمة إلى الشفرة التي استُدعِيت منها. يُفضَّل دائما تعريف الدوال قبل استخدامها. ترجمة - بتصرّف - للمقال Understanding JavaScript Functions لصاحبه Zell Liew.
-
عندما نكتب برنامجًا طويلًا جدًا، فإن الشيفرة ستوزَّع في عددٍ من الملفات والأصناف (classes) والدوال (functions)؛ الدوال هي مجموعة من التعليمات التي تنجز مُهمِّة معيّنة وهدفها ألا تكرر الشيفرات التي تكتبها؛ فمثلًا في نظام للاستيثاق، يكون هنالك دوال لتسجيل الدخول (login) والتسجيل (register) وتسجيل الخروج (logout). أبسط أشكال الدوال إن الشكل العام لأبسط دالة هو: <?php function function_name() { // الشيفرة } ?> وكما في المتغيرات، تستطيع إسناد أي اسم إلى الدالة (أعطينا الدالة في المثال السابق الاسم function_name). تُكتَب الشيفرة التي ستنفذها الدالة عندما يتم استدعاؤها بين أقواس معقوفة ({})؛ نستطيع استدعاء الدالة عبر كتابة اسمها ويليه أقواس عادية () كما في المثال الآتي: <?php // يمكنك أن تستدعي الدالة هنا قبل تعريفها // تعريف دالة ذات الاسم say_hello function say_hello() { // كل ما تفعله هذه الدالة هو طباعة hello echo "hello"; } // استدعاء الدالة say_hello(); ?> الدوال ذات الوسائط يمكننا تمرير المعلومات الإضافية (مثل اسم المستخدم وكلمة المرور) إلى الدوال باستخدام الوسائط (arguments)، وعلينا تعريف المعاملات (parameters). ملاحظة: الوسائط هي البيانات التي نمررها إلى الدالة عندما نستدعيها، أما المعاملات فهي المتغيرات التي نُعرِّفها عندما نكتب الشيفرة الخاصة بالدالة. يمكننا أن نعتبر أن المعاملات هي حاويات والوسائط هي البيانات التي نضعها في تلك الحاويات. <?php // دالة تسجيل الدخول ذات وسيطين function login($user, $pass) { // تطبع هذه الدالة اسم المستخدم وكلمة المرور echo "hello, username is $user and password is $pass"; } // استدعاء الدالة login("user1","UsEr!p@$$W0rD"); // استدعاء الدالة مرةً أخرى login("user2","simplepassword"); ?> المعاملات ذوات القيم الافتراضية يمكننا أن نعطي قيمًا افتراضية للمعاملات لكي يمكن تجاوز تحديد قيمتها عند استدعاء الدالة. <?php // دالة تسجيل الدخول ذات ثلاثة وسائط function login($user, $pass, $active = "not active") { // تعرِض هذه الدالة اسم المستخدم وكلمة مروره وحالته echo "hello, username is $user and password is $pass and user is $active"; } // استدعاء الدالة login('user1','UsEr!p@$$W0rD'); // استدعاء الدالة مرةً أخرى login('user2','simplepassword', 'active'); ?> ملاحظة: إن أردت ألّا تُحدِّد قيمةً لوسيطٍ ما عند استدعاء الدالة، فيجب أن يكون المعامل الموافق لذاك الوسيط في آخر القائمة كما في المثال السابق. ويملك المعامل افتراضيًا القيمة "null". الدوال ذات المعاملات متغيرة العدد يمكن أن تملك الدوال عددًا متغيرًا من المعاملات؛ وفي الواقع، تستطيع تمرير إي عدد من الوسائط إلى دالة؛ استعمل الدوال المُضمَّنة في PHP الآتية للوصول إلى تلك الوسائط: الدالة func_get_args(): تُعيد مصفوفة بجميع الوسائط المُمرَّرة الدالة func_num_args(): تُعيد العدد الإجمالي للوسائط المُمرَّرة. الدالة func_get_arg(argument_number): تُعيد المتغير ذو الرقم argument_number سنظهِر -في المثال الآتي- مجموع الأرقام المُمرَّرة إلى الدالة كوسائط بالإضافة إلى عرضها. <?php function sum() { // سنستعمل func_get_args() للحصول على كل المعاملات على شكل مصفوفة $ary = func_get_args(); print_r($ary); echo "<br>"; $sum = 0; // سنستعمل func_num_args للحصول على العدد الكلي للمعاملات for($i = 0; $i < func_num_args(); $i++) { // سنستعمل func_get_arg(index) للحصول على قيمة معامل معيّن echo func_get_arg($i).'<br>'; $sum+= func_get_arg($i); } echo "sum is $sum <br><br>"; } sum(1,2,3,4); sum(23,2343,54,2,1,6); ?> ناتج تنفيذ السكربت السابق هو: Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) 1 2 3 4 sum is 10 Array ( [0] => 23 [1] => 2343 [2] => 54 [3] => 2 [4] => 1 [5] => 6 ) 23 2343 54 2 1 6 sum is 2429 إعادة القيم من الدوال لاحظ أننا في المثال السابق طبعنا السلسلة النصية مباشرةً، لكن ماذا لو أردنا أن نجعل الدالة تُعيد قيمةً ما؟ نستعمل العبارة البرمجية return لإعادة قيمة من الدالة، وتُسبِّب هذه العبارة بإنهاء تنفيذ الدالة مباشرةً وإعادة القيمة إلى مكان استدعاء الدالة، لنرى مثالًا عن دالة تُعيد مربَّع العدد المُمرَّر إليها: <?php function square ($num) { return $num * $num; } // الناتج هو 16 echo square (4); ?> لاحظ أنك لا تستطيع إعادة أكثر من قيمة من الدالة، لكن يمكنك إعادة مصفوفة التي تؤدي نفس الدور تقريبًا. <?php function powers ($num) { return array ($num, $num * $num, $num * $num * $num); } // الناتج هو: Array ( [0] => 4 [1] => 16 [2] => 64 ) print_r(powers (4)); ?> مجالات تعريف الدوال تستطيع أن تستدعي الدوال المُعرَّفة في الأمثلة السابقة قبل مكان تعريفها، لأن مجالها (scope) هو المجال العام، يجدر بالذكر أنَّك تستطيع تعريف الدوال داخل جملة شرطية (if) لكن لا يمكنك استدعاؤها إن لم يتحقق الشرط كما في المثال الآتي: <?php $str = 'create the function'; global_function(); // لا يمكننا استدعاء الدالة not_global هاهنا، لأن المفسر لا يعتبرها موجودةً إن لم تتحقق الجملة الشرطية الآتية if ($str == 'create the function') { function not_global() { echo 'I don\'t exist until program execution reaches me'; } } // نستطيع الآن استدعاء الدالة not_global بعد اختبار أن السلسلة $str مساوية للقيمة اعلاه، لتجنب إظهار خطأ if ($str == 'create the function') not_global(); function global_function() { echo 'I exist immediately upon program start'; } ?> الأمر سيان لآلية تعريف دالة داخل دالة أخرى: <?php function global_function() { function not_global() { echo 'I don\'t exist until global_function() is called'; } } // لا يمكننا استدعاء not_global هنا، إذ علينا استدعاء global_function أولًا global_function(); // نستطيع الآن استدعاء الدالة not_global، لأن استدعاء global_function قد جعلها متاحةً للمفسر not_global(); ?> المتغيرات في الدوال مجال المتغيرات (variable scope) هو "المجال" الذي يبقى فيه المتغير مُعرَّفًا، أي بكلامٍ آخر، المتغيرات المُعرَّفة داخل الدوال لا يمكن الوصول إليها من خارج تلك الدوال؛ أما المتغيرات المُعرَّفة في المجال العام (global scope) يمكن الوصول إليها من أي جزء من البرنامج في المجال العام؛ ربما أربكك الشرح السابق لكن انظر إلى هذا المثال للتوضيح: <?php // المتغير $a في المجال العام $a = 1; function test() { echo $a; // لا يمكن الوصول إلى المتغير $a لأنه في المجال العام } // لن يظهر أي شيء ﻷن المتغير $a ليس ضمن مجال الدالة test(); // سيظهر الرقم 1، لأن المجال هو العام echo $a; ?> لن تظهر مخرجات عند استدعاء الدالة test() لأن الدالة echo داخلها تُشير إلى نسخة محلية من المتغير $a التي لم تُسنَد لها قيمة في ذاك المجال. يمكن الوصول إلى المتغيرات في المجال العام من داخل الدوال باستخدام الكلمة المحجوزة global كما يلي: <?php $a = 1; $b = 2; function sum (){ // أصبح بإمكاننا الوصول إلى المتغيرين في مجال الدالة الخاص، وتعديل قيمتهما مباشرةً global $a, $b; $b = $a + $b; } sum(); echo $b; ?> نوعٌ أخيرٌ هو المتغيرات الثابتة (static variables) التي يُسمَح بوجودها في مجال الدوال الخاص فقط، لكنها لا تفقد قيمتها عند انتهاء تنفيذ الدالة، انظر إلى المثال الآتي لتوضيح الأمور: <?php function test() { $a = 0; echo $a; $a++; } ?> الدالة السابقة عديمة الفائدة لأنها في كل مرة تُستدعى فيها ستضبط قيمة المتغير $a إلى 0، ثم ستُظهِر قيمة ذاك المتغير (التي هي صفر)، وأخيرًا لن نستفيد من زيادة قيمة المتغير ($a++) لانتهاء تنفيذ الدالة ولن يعود المتغير $a موجودًا. أما لو عرَّفنا المتغير $a على أنه ثابت، فلن يفقد قيمته بعد انتهاء تنفيذ الدالة: <?php function test() { static $a = 0; echo $a; $a++; } ?> ستتم تهيئة المتغير $a في أول مرة تُستدعى فيها الدالة، وستُطبَع قيمة المتغير وستزداد قيمته في كل مرة تستدعى فيها الدالة مرةً أخرى. <?php function test() { static $a = 0; echo $a; $a++; } //الناتج 0 test(); //الناتج 1 test(); //الناتج 2 test(); ?> ملاحظة: يجب إسناد قيم بسيطة إلى المتغيرات الثابتة عند تعريفها، إذ لا يجوز استعمال التعابير الرياضية أو إسناد القيم المُعادة من الدوال إليها. المعاملات المرجعية رأينا كيف أنَّ جميع الدوال السابقة تعيد قيمة ما بناءً على العمليات التي تُجرى فيها، لكنها لا تستطيع تعديل قيم الوسائط المُمرَّرة إليها، لكن "التمرير بالمرجعية" (pass by reference) يسمح للدوال بتعديل قيم الوسائط مباشرةً، لنأخذ مثالًا بسيطًا يوضِّح هذا الأمر: <?php function test(&$var) { $var++; // لاحظ عدم استعمال عبارة return هنا } $a = 5; test($a); echo $a; // الناتج هو 6 ?> الاختلاف الوحيد الذي يجعل الوسائط تُمرَّر بمرجعيتها هو وضع محرف «&» قبل اسم الوسيط عند تعريف الدالة. الدوال المجهولة الدوال المجهولة (anonymous functions) التي تُعرَف أيضًا بالمصطلح "closures" تسمح بإنشاء دالة ليس لها اسم محدد، وإنما تُسند مباشرةً إلى متغير مَثَلُها كَمَثَلِ أيّةِ عملية إسنادٍ أخرى، وتنتهي عملية الإسناد أيضًا بفاصلة منقوطة؛ هذا مثالٌ عنها: <?php $square = function ($num) { echo $num * $num; }; $square(2); // الناتج 4 $square(15); // الناتج 225 ?> نستطيع أن نُمرِّر إلى الدوال المجهولة أي متغير موجود في مجال المتغيرات الأعلى منها وذلك باستخدام الكلمة المحجوزة use، تأمّل في المثال الآتي وفي تعليقاته: <?php $message = 'hello'; // لم نستعمل الكلمة المفتاحية use هنا $example = function () { echo $message; }; $example(); // لن تَظهَر أيّة قيمة (أو بالتحديد، سيظهر خطأ Notice ﻷن المتغير غير مُعرَّف) // تمرير المتغير $message $example = function () use ($message) { echo $message; }; $example(); // الناتج: hello // القيمة المُمرّرة تؤخذ قبل تعريف الدالة، وليس قبل استدعائها $message = 'world'; $example(); // الناتج: hello // إعادة قيمة المتغير إلى قيمته الأصلية $message = 'hello'; // الوراثة بالمرجعية (inherit by-reference) $example = function () use (&$message) { echo $message; }; $example(); // الناتج: hello // إذا تغيرت قيمة المتغير الآن، فستتأثر الدالة المجهولة بها $message = 'world'; $example(); // الناتج: world // استعمال الوسائط العادية $example = function ($arg) use ($message) { echo $arg . ' ' . $message; }; $example("hello"); // الناتج: hello world ?> تمرين اكتب دالةً تقبل وسيطين أولهما هو طول المستطيل والآخر هو عرض المستطيل، وستعيد هذه الدالة أربع قيم تُمثِّل إحداثيات نقاط التقاء أضلاعه على فرض أنَّ مركزه يقع على مبدأ الإحداثيات. المصادر مقال Functions in php لصاحبه Harish Kumar. مقالتي Functions و Closures لصاحبهما Dayle Rees. صفحات Functions و Anonymous functions و User-defined functions في دليل php وغيرها.
-
عندما يزداد طول البرامج وتعقيدها، فستزداد صعوبة تصميمها وبرمجتها وصيانتها؛ لذا من المفيد عادةً تقسيم المهام الكبيرة إلى سلسلة من المهام الأصغر. سنُقسِّم في هذا الدرس السكربت الذي كنا نعمل عليه إلى عدد من الدوال (functions) المنفصلة. لكي نتعرف على مفهوم الدوال، فلنحاول وصف طريقة القيام بمهمة يومية: الذهاب إلى السوق وشراء الطعام. تخيل أننا سنصف العملية إلى كائنات فضائية آتية من المريخ. سيبدو الوصف العام لعملية شراء الطعام كالآتي: غادر المنزل قد السيارة إلى السوق اركن السيارة ادخل السوق اشترِ طعامًا قد السيارة إلى المنزل اركن السيارة ادخل إلى المنزل سيُغطِّي الشرح السابق الآلية العامة للذهاب إلى السوق؛ لكن تلك الكائنات الفضائية ستحتاج مزيدًا من التفاصيل، فمثلًا يمكن وصف المهمة الفرعية "اركن السيارة" كالآتي: اعثر على مكان فارغ لركن السيارة قد السيارة إلى ذاك المكان أطفئ المحرك "ارفع" المكابح اليدوية اخرج من السيارة اقفل السيارة ويمكن بالطبع تقسيم خطوة "أطفئ المحرك" إلى عدد من الخطوات مثل: أطفئ دارة الإشعال أخرج مفتاح السيارة وهكذا إلى أن تُفصِّل كل خطوة من كامل عملية الذهاب إلى السوق. عملية تعريف الخطوط الأساسية ومن ثم كتابة التفاصيل لتلك الخطوات تسمى "نمط تصميم Top-Down". يسمح هذا النمط لنا بتقسيم المهام الكبيرة والضخمة إلى مهام أبسط وأصغر. سنستخدم نمط تصميم Top-Down ليساعدنا في التخطيط لبرنامجنا الذي سنكمل تطويره وإضافة الميزات إليه. يمكننا تلخيص "الوصف العام" للمهام التي يقوم بها السكربت الآن: بداية الصفحة بداية ترويسة الصفحة كتابة العنوان إغلاق الترويسة بداية جسم الصفحة كتابة العنوان كتابة بصمة الوقت (timestamp) إغلاق الجسم إغلاق الصفحة تمت برمجة كل الخطوات السابقة، لكننا نريد إضافة المزيد. لندرج بعض المهام الإضافية بعد المهمة السابعة: كتابة بصمة الوقت كتابة معلومات عن إصدار النظام كتابة الوقت الذي مضى منذ آخر تشغيل (uptime) كتابة مساحة القرص كتابة المساحة التخزينية لمجلدات المنزل (home) إغلاق الجسم إغلاق الصفحة سيكون من حسن حظنا وجود أوامر تستطيع تنفيذ المهام الإضافية، فسنستطيع استخدام "تعويض الأوامر" (command substitution) لوضعها في السكربت كالآتي: #!/bin/bash # sysinfo_page - A script to produce a system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ أما للمهام التي لا توجد أوامر تستطيع فعل ما نريد تحديدًا، فيمكننا إنشاؤها باستخدام دوال الصدفة (shell functions). وكما تعلمنا في أحد الدروس السابقة، يمكن اعتبار دوال الصدفة على أنها "برامج صغيرة ضمن البرامج" وتسمح لنا باتباع مبادئ نمط التصميم top-down. علينا تعديل السكربت كالآتي لإضافة دوال الصدفة: #!/bin/bash # sysinfo_page - A script to produce an system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Functions system_info() { } show_uptime() { } drive_space() { } home_space() { } ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ هنالك نقطتان تجدر الإشارة إليهما: أولهما أنَّه يجب تعريف دوال الصدفة قبل محاولة استخدامها؛ وثانيهما هو أنَّ جسم الدالة (أي القسم الذي يقع بين قوس البداية "}" وقوس النهاية "{") يجب أن يحتوي على أمرٍ واحدٍ على الأقل. لن يعمل السكربت السابق وسيُظهِر رسالة خطأ وذلك لأنَّ جسم الدوال فارغ. أبسط طريقة لتصحيح هذه المشكلة هي وضع عبارة "return" في جسم كل دالة، وبعدها سيُنفَّذ السكربت بنجاح. إبقاء السكربتات قابلة للتشغيل من المفيد أثناء تطويرنا للتطبيق أن نُضيف جزءًا يسيرًا من الشيفرات ثم نُجرِّب السكربت ثم نضيف المزيد ثم نجرِّب السكربت وهكذا. وبهذه الطريقة سيسهل العثور على الأخطاء في الشيفرة ومن ثم تصحيحها. بعد إضافة الدوال إلى السكربت، أصبح بإمكانك الآن مراقبة التسلسل المنطقي لتنفيذ السكربت وذلك عبر آلية يُطلَق عليها اسم stubbing أي إضافة شيفرة وهمية. يمكنك تخيل هذه الآلية كما يلي: لنفترض أننا نريد إنشاء دالة اسمها "system_info" لكننا لم نفكر في تفاصيل الشيفرة بشكل كامل. فبدلًا من إيقاف عملية تطوير السكربت إلى أن ننتهي من الدالة system_info فيمكننا إضافة الأمر echo إليها كالآتي: system_info() { # Temporary function stub echo "function system_info" } سنتمكن باستخدام هذه الآلية من تنفيذ السكربت دون خطأ حتى لو لم نكمل برمجة الدالة system_info؛ ونستطيع لاحقًا وضع الشيفرة الحقيقية بدلًا من أمر echo السابق. سبب استخدامنا لأمر echo هو أننا نحتاج إلى مؤشر لكي نعرف أنَّ السكربت قد نفَّذ الدالة المعنية. لنُطبِّق هذه الآلية على جميع الدوال في السكربت: #!/bin/bash # sysinfo_page - A script to produce an system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Functions system_info() { # Temporary function stub echo "function system_info" } show_uptime() { # Temporary function stub echo "function show_uptime" } drive_space() { # Temporary function stub echo "function drive_space" } home_space() { # Temporary function stub echo "function home_space" } ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ سنكمل الآن العمل على كل دالة على حدة لكي تُخرِج معلوماتٍ مفيدةً. show_uptime ستُظهِر الدالة show_uptime ناتج الأمر uptime، الذي يعرض عدِّة معلومات مثيرة للاهتمام حول النظام، بما في ذلك المدة الزمنية منذ آخر إعادة تشغيل، وعدد المستخدمين، والحِمل (load) الحالي على النظام. $ uptime 9:15pm up 2 days, 2:32, 2 users, load average: 0.00, 0.00, 0.00 لعرض ناتج الأمر uptime في صفحة HTML، فسنحتاج إلى برمجة دالة الصدفة كالآتي (وذلك بعد حذف الشيفرة الوهمية التي كانت فيها): show_uptime() { echo "<h2>System uptime</h2>" echo "<pre>" uptime echo "</pre>" } كما ترى، تُخرِج الدالة السابقة نصًا يحتوي على خليطٍ من وسوم HTML مع مخرجات الأمر uptime؛ وستصبح هذه المخرجات جزءًا من here script عندما تُجرى عملية "تعويض الأوامر" في الجزء الرئيسي من السكربت. drive_space تستخدم الدالة drive_space الأمر df لتوفير ملخص للمساحة التخزينية المستهلكة من أنظمة الملفات الموصولة (mounted file systems). $ df Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda2 509992 225772 279080 45% / /dev/hda1 23324 1796 21288 8% /boot /dev/hda3 15739176 1748176 13832360 12% /home /dev/hda5 3123888 3039584 52820 99% /usr ستبدو بنية دالة dive_space شبيهةً للغاية بدالة show_uptime: drive_space() { echo "<h2>Filesystem space</h2>" echo "<pre>" df echo "</pre>" } home_space ستُظهِر دالة home_space مقدار المساحة التخزينية التي يستهلكها كل مستخدم في مجلد المنزل الخاص به. سيُعرَض الناتج كقائمة مرتبة تنازليًا وفق مقدار المساحة التخزينية المستخدمة. home_space() { echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" } لاحظ أنَّه يجب تنفيذ السكربت عبر مستخدم يملك امتيازات إدارية لكي تعمل الدالة السابقة بشكلٍ صحيح، لأنَّ الأمر du يتطلب امتيازات الجذر (root) لكي يتفحص محتويات المجلد /home. system_info لسنا جاهزين بعد لإكمال دالة system_info. لكننا سنُحسِّن من الشيفرة الوهمية التي فيها لكي تُنتِج وسوم HTML: system_info() { echo "<h2>System release info</h2>" echo "<p>Function not yet implemented</p>" } ترجمة -وبتصرّف- للمقالَين Shell Functions و Some Real Work لصاحبهما William Shotts.
-
في المصنفات التي تحتوي على أكثر من ورقة عمل، نحتاج أحيانا إلى الرجوع إلى خلية أو نطاق من الخلايا في أوراق متعددة ذات نمط متشابه عند كتابة صيغة ما. في هذه الحالة يمكننا تجّنب الصيغ المعقدة، أو نسخ الخلايا من ورقة إلى أخرى باستخدام المراجع ثلاثية الأبعاد. البنية العامة للصيغة هي: =Function (first worksheet:last worksheet!cell reference) Function: أي دالة تريد استخدامها، كدالة الجمع، المعدل... إلخ. First worksheet: اسم ورقة العمل الأولى في النطاق. Last worksheet: اسم ورقة العمل الأخيرة في النطاق. Cell reference: اسم الخلية التي تريد تطبيق الدالة عليها في جميع الأوراق ضمن النطاق. وسنوضّح طريقة كتابة الصيغة ثلاثية الأبعاد في الأمثلة التالية: مثال1: في هذا المثال لدينا درجات الاختبارات لمجموعة من الطلاب لأربعة أشهر، وقد تم إدخال درجات كل شهر في ورقة منفصلة (... ,Month1, Month2). المطلوب هو حساب قيمة متوسط الدرجات في ورقة منفصلة (Average): سنقوم أولا بتحديد الخلية التي نريد إظهار نتيجة المتوسط فيها، وهي الخلية B2 في الورقة "Average". ثم سنكتب الصيغة التالية: =average( سننتقل إلى الورقة الأولى في النطاق "Month1"، سنلاحظ في شريط الصيغة إدخال اسم الورقة تلقائيا في الصيغة متبوعا بعلامة تعجب (!)، وهذا يدل على استخدام الورقة الأولى كمرجع: بعدها سنحدد أول قيمة نريد إدخالها في دالة المتوسط، وهي درجة الطالب "زيد ثابت" في الشهر الأول، أي الخلية B2 في الورقة "Month1": ثم سنضغط المفتاح Shift وننقر على آخر ورقة في النطاق "Month4" مع الاستمرار بالضغط، ثم Enter لتطبيق الصيغة: وبذلك تم إيجاد قيمة المتوسط لدرجات اختبارات الطالب الأول للأشهر الأربعة في الورقة "Average" (لاحظ الصيغة في شريط الصيغة). أي ببساطة أننا قمنا بإخبار البرنامج أن يقوم بإيجاد المتوسط لجميع القيم في الموقع B2 من الورقة الأولى حتى الورقة الأخيرة في النطاق. بعد ذلك سنقوم باستخدام التعبئة التلقائية لتطبيق الصيغة على بقية الخلايا في الجدول: من فوائد المراجع ثلاثية الأبعاد هي أنّ قيمة المتوسط ستتغير تبعا لأي تحديث نجريه على أي ورقة من أوراق النطاق. ولكي تتوضح الخطوات السابقة أكثر، شاهد الصورة أدناه: مثال2: هذا المثال يحتوي على ثلاثة أوراق. تحتوي الورقة الأولى "الفرع الأول" على مبيعات الفرع الأول لأحد المتاجر لمجموعة من المنتجات، الورقة الثانية "الفرع الثاني" على مبيعات الفرع الثاني... وهكذا. المطلوب هو إيجاد مجموع المبيعات لكل منتج لكل فرع وللأرباع الأربع: سنقوم أولا بتحديد الخلية التي سيظهر فيها ناتج المجموع للمنتج الأول، وهي B4 في الورقة "المجموع"، ثم سنستخدم دالة الجمع بالصيغة التالية: =sum( ثم سننتقل إلى الورقة الأولى "الفرع الأول" ونحدد الخلية B4: نضغط المفتاح Shift ونحدد الورقة الثالثة "الفرع الثالث" مع الاستمرار بالضغط ليتحدد جميع نطاق الأوراق، ثم نضغط Enter لإيجاد النتيجة: وسنستخدم التعبئة التلقائية لتطبيق الصيغة على جميع الخلايا في الجدول. الصورة أدناه توضح خطوات هذا المثال من البداية: فيما يلي مجموعة الدوال التي تدعم استخدام المراجع ثلاثية الأبعاد في اكسل: SUM: لإيجاد مجموع مجموعة من القيم الرقمية AVERAGE: لإيجاد متوسط مجموعة من القيم الرقمية AVERAGEA: لإيجاد متوسط مجموعة من القيم الرقمية، النصية، والمنطقية COUNT: لحساب عدد الخلايا التي تحتوي على أرقام COUNTA: لحساب عدد الخلايا غير الفارغة MAX: لإرجاع أكبر قيمة ضمن مجموعة من الخلايا MAXA: لإرجاع أكبر قيمة ضمن مجموعة من الخلايا، بما فيها النصوص والقيم المنطقية. MIN: لإرجاع أصغر قيمة ضمن مجموعة من الخلايا MINA: لإرجاع أصغر قيمة ضمن مجموعة من الخلايا، بما فيها النصوص والقيم المنطقية. PRODUCT: لإيجاد حاصل ضرب مجموعة من القيم الرقمية STDEV ،STDEVA ،STDEVP ،STDEVPA: لحساب الانحراف المعياري لمجموعة من القيم المحددة استنادا إلى عينة أو لمحتوى بأكمله. VAR ،VARA ،VARP ،VARPA: لإرجاع قيمة التباين لمجموعة من القيم المحدد استنادا إلى عينة أو لمحتوى بأكمله.
-
- 3d reference
- اكسل
-
(و 7 أكثر)
موسوم في: