الخميس، 1 أكتوبر 2015

الفرق بين print و return

الفرق بين print و return
أنهيت كتابة المقالة بتاريخ:
12:39 AM 1-10-2015


بسم الله الرحمن الرحيم

كثير من الأسئلة والأفكار تدور في ذهن المتعلم حول هاتين الإفادتين(statments)، فعندما تقرأ في كتاب أو دورة ما لا يتم أخذهما بتعمق فيصبح المتعلم مشوشا ولا يعرف كيفية الإستفادة الحقيقية من خواصهما، في هذه المقالة سأتحدث عن هذا الأمر مدعما كتاباتي بالأمثلة، راجيا من الله عز وجل التوفيق.

أولا.. سأبدأ بلمحة عامة عن هاتين الإفادتين.
الإفادة print‏ ‏:
هي إفادة في بايثون 2 ولكنها أصبحت دالة(function) في بايثون 3 لأسباب وجيهة، تقوم بطباعة الخرج الناتج عن عملية ما أو بطباعة قيمة ما مخزنة في متغير على سبيل المثال.

الإفادة return‏ ‏:
تعود بقيمة من دالة ما؛ تقوم بعملية إستعادة قيمة دالة ما، هذا ما يجب أن تركز عليه وسأشرح بتفصيل أكثر.
#################################################################################

قبل البدء سأعرض سؤالين أكاد أجزم أنهما راوداك وسأجيب لك عنهما؛ لكنهما ليسا الصورة الكاملة إن صح التعبير. ستضح الكثير من الأمور ولكن ليس كلها o‎_O.

س1: أين تستخدم الإفادتان؟
تستخدم الإفادة print في كل مكان تقريبا، وتستخدم الإفادة return داخل الدوال حصرا‎‏ وإذا استخدمت خارج الدوال فإن الخطأ SyntaxError سيعتلي.
مثال 1.0: شفرة تعمل بنجاح

مثال 1.1: شفرة خاطئة
 
#################################################################################

س2: متى تستخدم الإفادتين؟
تستخدم الإفادة print عند الحاجة لطباعة الخرج مباشرة على الشاشة، وتستخدم الإفادة return عند الحاجة لحفظ الخرج في الذاكرة(مثلا: إسناد الخرج إلى متغير) أو إستخدام الخرج في عملية أخرى مباشرة(مثلا: إستخدام خرج دالة ما في عمليات دالة أخرى) أو أشياء أخرى من هذا القبيل.
مثال 2.0: طباعة الخرج مباشرة على الشاشة
مثال 2.1: إسناد الخرج إلى متغير
هذه الطريقة تجنبنا مشاكل إستخدام متغيرات عالمية global.

مثال 2.2: إستخدام الخرج في عمليات أخرى
الدالة multiply2 عادت بالدالة sum2 وهذا يعد أحد أنواع مزينات/مزخرفات decorators بايثون(دالة تعود بدالة أخرى).
======================================================================
======================================================================

*. أعتقد أن جواب السؤال الأول وضح المقصد بيسر وسهولة!
*. برأيي جواب السؤال الثاني لم يوضح بالشكل المطلوب فالأمر أوسع من هذا..!، ما رأيك أنت؟
==> لذا سأستطرد بالشرح أكثر إعتمادا على أمثلة جواب السؤال الثاني.
- إذا لاحظت في المثال 2.0 ، جسم الدالةsum1 ‎‏ يعطي الخرج مطبوعا على مباشرة عند تنفيذ الشفرة وهذا نقيض للمثال 2.1 حيث أن جسم الدالة المعدلة فيه sum2 لا يعطي الخرج مطبوعا بل يمسك به.، لتوضيح الفكرة أكتب/إلصق الشفرة التالية على محررك ونفذها(أكتب قبله الدالتين المستخدمتين)‎:
 
سنحصل بعد التنفيذ على الخرج التالي:
6
حسنا، شيء غريب حصل، إن 6 نتاج الدالة الأولى لكن أين نتاج الدالة الثانية؟ يفترض أن يطبع تحت '6' الناتج: 8 ، أين ذهب؟ ماذا حصل؟
سأقول لك ما الذي حدث، في الدالة الأولى لا يتم إعادة أي قيمة بل يتم إخراج القيمة مباشرة على الشاشة والقيمة المعادة عندها: 'لا شيء' None‏ ‏، أما في الدالة الثانية لا يتم إخراج أي قيمة مباشرة على الشاشة بل يتم إعادة القيمة ،والقيمة المعادة عندها: 8 لكنها لا تطبع.. إذا لتطبعها على الشاشة ستحتاج لإستخدام print‏ ، فالنرى إذا التالي ‏(قم بتنفيذ الشفرة):
 
بعد التنفيذ سنحصل على التالي:
6
None
8
كما ترى فهناك قيمتان جديدتان ظهرتا على شاشتنا، هما: None‏ و 8، إن None‏ القيمة المعادة من الدالة الأولى و 8 هي القيمة المعادة من الدالة الثانية.. هذا ما أردت أن أريك إياه :)

*. سؤال يطرح نفسه الآن، لعلك فكرت به:
س3: متى تكون قيمة الدالة المعادة 'لا شيء' None‏ ؟
صراحة هناك عدة حالات، لا أعلم لعلي سأوردها كلها الآن أو قد يغيب عن ذهني بعضها، سأوردها الآن فركز معي:
-> أول حالة، أن يكون جسم الدالة فارغا!، سأستخدم الإفادة pass‏ لهذا الغرض.
مثال 3.0: دالة ذات جسم فارغ(دالة فارغة)
-> ثان حالة، أن يكون جسم الدالة ليس فارغا لكن يتم إخراج القيم مباشرة، عد إلى المثال 2.0 وتمعن به ==> لم نعطي الدالة قيمة لتقوم بإعادتها.
-> ثالث حالة، أن تكتب في جسم الدالة إفادة return فارغة!
مثال 3.1: دالة ذات إفادة  return فارغة!

======================================================================

إذا كنت تظن أننا إنتهينا، فأنت مخطئ فكل الذي سبق كان أول جزء، الآن سنتابع حديثنا الشيق..

سأتحدث عن حاجز return، نعم لا تستغرب، هذا الحاجز يوجد عند إقحام return‏ في جسد أي دالة، وكما في الجزء الأول أعلاه؛ سأطرح عدة أسئلة واضعا الإجابات بعون الله.
س4: بماذا يقوم حاجز return‏ ‏؟ ماذا يفعل؟
ببساطة، هذا الحاجز يسمح بتنفيذ الشفرات التي تسبقه كالمعتاد(عد إلى المثال 3.1 وإقرأ الدالة الثانية بتمعن) ويمنع تنفيذ الشفرات التي تأتي بعده أي يتجاهلها!
بينما الإفادة print‏ لا تضع هكذا حاجز فهي تسمح بتنفيذ الشفرات التي قبلها والتي بعدها أيضا.
مثال 4.0 : تجاهل الشفرات اللاحقة
ستحصل على الخرج التالي:
I Love Allah
And All Its Messengers
Praying Is The Food Of My Soul
كما لاحظت، لم يتم تنفيذ الشفرة التي تلي return‏ ‏؛ توقف تنفيذ الدالة عند شفرة return.

س5: بماذا يفيد هذا الحاجز؟
عند وجود هذا الحاجز فإنه يعطي الدالة إشارة أن هذه قيمتك المعادة وقد حصلتي على مرادك أخيرا عندها تتوقف الدالة عند هذا السطر وينتهي عمل الدالة -لكن هناك إستثناءات-.
*. عادة أستفيد من هذه الخاصية في دالة كتبتها لمعرفة فيما إذا كانت القيمة التي حصلت عليها من عملية ما قابلة-للترديد iterable‏ أم لا (مثلا: كأن أحصل على قائمة من أرقام مختلفة أو أحصل على رقم لوحده)، هذه دالتي:
مثال 5.0 : دالة لها أكثر من إفادة return واحدة.

======================================================================

قد يتبادر للذهن بأن كل ما كتبته من أمثلة عن return‏ ‏، جعلت فيها return‏ تعود بقيمة واحدة.. أعتقد فهمت مقصدي من هذا الكلام.

[6] إفادة return‏ تعود بأكثر من قيمة واحدة!
حسنا، أعترف القيام بمثل هكذا أمر ليس إلا خداعا، فمهما فعلت سيكون عدد القيم المعادة واحد '1'، سيتم الأمر بأن أعيد أكثر من قيمة داخل حاوية واحدة أو حاويات فرعية لحاوية رئيسية ما.. الفكرة لازالت مشوشة ومبهمة قليلا أليس كذلك؟ فالنرى المثال التالي وسيبدأ الضباب بالإنقشاع:
مثال 6.0: دالة تعود بأكثر من قيمة!
وستحصل على الخرج التالي:
(1, 2, 3)
كما قد لاحظت، حصلنا على قيمة واحدة رئيسية وهي الصف tuple‏ من خلال وضعنا للفاصلة بين القيم المعادة ‏(الصف هو الحاوية الإفتراضية default) وبداخله ثلاثة قيم(أرقام) نستطيع إستخدامها من خلال الولوج إليها عبر المؤشر index الخاص بكل قيمة فرعية.
يمكن أن نعود بالقيم المتعددة بحاويات أخرى غير الصف كالقائمة list مثلا، هكذا:
return [a, b, c]
أو:
return list(a, b, c)

كإستراحة قصيرة تفقد المثال التالي[ليس تعليميا وليس لغرض المقارنة]
مثال 6.1: رؤية قيم متعددة في الخرج!
ستحصل على الخرج التالي:
my name is samer
('my name is', 'samer')


سؤال سأله أحد الذين يتعلمون بايثون، هو كالتالي:
س7: هل يمكن وضع أكثر من إفادة return‏ في دالة واحدة وتعمل بنفس الوقت؟
أعتقد أنك يجب أن تجيب بسهولة: لا
- يمكن وضع أكثر من إفادة لكن كل واحدة تعمل عند حدوث شرط أو حدث ما(عد للمثال 5.0 وتمعن به).
مثال 7.0: عدم عمل الإفادات المتتابعة
ستحصل على الخرج التالي:
I'm The Only Retured Value Here

======================================================================

[8] آخر ما سأتحدث عنه هو إفادة return‏ الحلزونية 'هكذا أحب تسميتها :)' ، على عكس إفادة print‏ فإن الإفادة return‏ تسمح بإعادة العملية ضمن نفس الدالة أكثر من مرة!! (هذا الإستثناء الذي تحدثت عنه في جواب السؤال 5)، هذه الطريقة أستفيد منها في العديد العديد من الأمور من أشهرها دالة لإيجاد: ن عاملي لرقم ما n factorial‏ ‏، تفقد المثال التالي:
مثال 8.0: الإستفادة من إفادة حلزونية


أتممت هذه المقالة بعد عناء بعون وفضل من الله والحمد لله رب العالمين وأفضل الصلاة وأتم التسليم على حبيبنا محمد خاتم الأنبياء والمرسلين صلى الله عليه وسلم.
والسلام عليكم ورحمة الله وبركاته

إذا كانت لديك أي ملاحظة أو إستفسار أو تحسين مقترح أو فكرة غفلت عنها .. رجاء أكتب ذلك في تعليقات المقالة دون تردد.

هناك 14 تعليقًا:

  1. شرح ليس للمبتدئين بل للمتقدمين ومشكور

    ردحذف
    الردود
    1. شكرًا على إبداء رأيك فهو يهمني.

      حذف
    2. لقد ذكرت: "شرح ليس للمبتدئين بل للمتقدمين".
      هل هذا أمر سيء أم جيد؟

      حذف
  2. مهم وجميل ويوضح الكثير

    ردحذف
    الردود
    1. مسرور لأنه أعجبك، هل من ملاحظات!.

      حذف
  3. مشكور على الشرح الرائع
    أنا في اسبوع كامل ابحث عن الاجابة و حمد الله كما ان الشرح دقيق و مفهوم

    ردحذف
    الردود
    1. شكرًا على تعليقك، هل من مُلاحظات؟!

      حذف
  4. جزاك الله خيراً ،لقد أجبت عن سؤال كان يحيرنى

    ردحذف
    الردود
    1. شكرا، هل من اقتراحات أو ملاحظات؟

      حذف
  5. لم افهم هدف المثال الاخير

    ردحذف
  6. بصراحة افدتني جدا
    شكرا جزيلا و وفقك الله

    ردحذف
  7. شكرا لك.

    ردحذف