python - ماذا يفعل إذا __name__=="__main__":هل؟




namespaces python-module idioms (23)

ماذا if __name__ == "__main__": هل؟

# Threading example
import time, thread

def myfunction(string, sleeptime, lock, *args):
    while True:
        lock.acquire()
        time.sleep(sleeptime)
        lock.release()
        time.sleep(sleeptime)

if __name__ == "__main__":
    lock = thread.allocate_lock()
    thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
    thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

Answers

عندما تكون هناك عبارات معينة في الوحدة النمطية لدينا ( M.py ) نريد أن يتم تنفيذها عند تشغيلها على أنها رئيسية (غير مستوردة) ، يمكننا وضع هذه البيانات (حالات الاختبار ، وكشوف الطباعة) تحت هذا في if الحظر.

كما افتراضياً (عند تشغيل الوحدة النمطية الرئيسية ، لا يتم استيرادها) يتم تعيين متغير __name__ إلى "__main__" ، وعندما يتم استيراده ، __name__ المتغير __name__ على قيمة مختلفة ، على الأرجح اسم الوحدة النمطية ( 'M' ). هذا مفيد في تشغيل تنويعات مختلفة لوحدات معا ، وفصل بيانات المدخلات والمخرجات الخاصة بهم وأيضاً إذا كانت هناك أي حالات اختبار.

باختصار ، استخدم هذا " if __name__ == "main" " لمنع تشغيل كود (معين) عند استيراد الوحدة.


إذا تم استيراد ملف .py هذا عن طريق ملفات .py أخرى ، فلن يتم تنفيذ الشفرة ضمن "بيان if".

إذا تم تشغيل هذا .py بواسطة python this_py.pyshell ، أو النقر المزدوج في Windows. سيتم تنفيذ الكود الموجود تحت "بيان if".

هو مكتوب عادة للاختبار.


وهو خاص عندما يتم استدعاء ملف Python من سطر الأوامر. يستخدم هذا عادة لاستدعاء وظيفة "main ()" أو تنفيذ تعليمات برمجية بدء تشغيل مناسبة أخرى ، مثل التعامل مع وسائط سطر الأوامر على سبيل المثال.

يمكن كتابتها بعدة طرق. آخر هو:

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

أنا لا أقول يجب عليك استخدام هذا في رمز الإنتاج ، لكنه يعمل على توضيح أنه لا يوجد شيء "سحري" حول if __name__ == '__main__' . إنها اتفاقية جيدة لاستدعاء وظيفة رئيسية في ملفات بايثون.


هناك الكثير من الطرق المختلفة هنا في ميكانيكا الكود المعني ، "كيف" ، ولكن بالنسبة لي لم يكن أي شيء منطقيًا حتى فهمت "لماذا". يجب أن يكون هذا مفيدًا بشكل خاص للمبرمجين الجدد.

خذ الملف "ab.py":

def a():
    print('A function in ab file');
a()

وملف آخر "xy.py":

import ab
def main():
    print('main function: this is where the action is')
def x():
    print ('peripheral task: might be useful in other projects')
x()
if __name__ == "__main__":
    main()

ما هو هذا الرمز في الواقع؟

عند تنفيذ xy.py ، تقوم import ab . تقوم جملة الاستيراد بتشغيل الوحدة فورًا عند الاستيراد ، بحيث يتم تنفيذ عمليات ab قبل باقي بيانات xy . بمجرد الانتهاء من ab ، فإنه يستمر مع xy .

يقوم المترجم بتتبع البرامج النصية التي تعمل مع __name__ . عندما تقوم بتشغيل برنامج نصي - بغض النظر عن ما "__main__" - يسميه المترجم "__main__" ، مما يجعله البرنامج الرئيسي أو البرنامج النصي "المنزل" الذي يتم إرجاعه بعد تشغيل برنامج نصي خارجي.

أي برنامج نصي آخر يسمى هذا البرنامج النصي "__main__" يتم تعيين اسم الملف الخاص به كـ __name__ (على سبيل المثال ، __name__ == "ab.py" ). ومن ثم ، فإن السطر if __name__ == "__main__": هو اختبار المترجم لتحديد ما إذا كان يقوم بتفسير / تحليل النص البرمجي "الرئيسي" الذي تم تنفيذه في البداية ، أو إذا كان ينظر بشكل مؤقت إلى برنامج نصي آخر (خارجي). وهذا يعطي المرونة للمبرمج لجعل البرنامج النصي يتصرف بشكل مختلف إذا تم تنفيذه مباشرة مقابل.

دعونا ننتقل إلى الشفرة المذكورة أعلاه لفهم ما يحدث ، مع التركيز أولاً على الأسطر غير الثابتة والترتيب الذي تظهر به في النصوص. تذكر أن وظيفة - أو كتل - لا تفعل أي شيء من تلقاء نفسها حتى يتم استدعاؤها. ما قد يقوله المترجم إذا تمتم إلى نفسه:

  • افتح xy.py كملف "home" ؛ نسميها "__main__" في المتغير __name__ .
  • استيراد وفتح الملف مع __name__ == "ab.py" .
  • أوه ، وظيفة. سوف اتذكر ذلك.
  • حسنا ، وظيفة a() ؛ أنا تعلمت ذلك للتو. الطباعة " وظيفة في ملف ab ".
  • نهاية الملف؛ العودة إلى "__main__" !
  • أوه ، وظيفة. سوف اتذكر ذلك.
  • واحدة أخرى.
  • وظيفة x() ؛ حسنا ، طباعة " مهمة طرفية: قد تكون مفيدة في مشاريع أخرى ".
  • ما هذا؟ بيان if . حسنًا ، تم استيفاء الشرط (تم تعيين المتغير __name__ إلى "__main__" ) ، لذلك سأقوم بإدخال الوظيفة main() وطباعة " الوظيفة الرئيسية: هذا هو المكان الذي يكون فيه الإجراء ".

تعني السطرين "__main__" : "إذا كان هذا هو البرنامج النصي "__main__" أو" home "، "__main__" تنفيذ الدالة المسماة main() ". ولهذا السبب سترى def main(): حظر أعلى ، والذي يحتوي على التدفق الرئيسي لوظيفة البرنامج النصي.

لماذا تنفيذ هذا؟

تذكر ما قلته في وقت سابق عن بيانات الاستيراد؟ عندما تقوم باستيراد وحدة ، فإنها لا "تتعرف" عليها فقط وتنتظر المزيد من التعليمات - فهي في الواقع تدير جميع العمليات القابلة للتنفيذ الموجودة داخل البرنامج النصي. لذا ، فإن وضع اللحم الخاص بك في الوظيفة main() عزله بشكل فعال ، ووضعه في عزلة بحيث لا يتم تشغيله فورًا عند استيراده بواسطة نص برمجي آخر.

مرة أخرى ، سيكون هناك استثناءات ، ولكن الممارسة الشائعة هي أن main() عادة لا يتم استدعائها خارجيًا. لذلك قد تتساءل عن شيء آخر: إذا لم نكن ندعو main() ، فلماذا نسمي النص على الإطلاق؟ يرجع السبب في ذلك إلى قيام العديد من الأشخاص ببناء نصوصهم باستخدام وظائف مستقلة تم إنشاؤها ليتم تشغيلها بشكل مستقل عن بقية الشفرة في الملف. ثم يطلق عليها لاحقاً في مكان آخر في نص البرنامج النصي. الذي يقودني إلى هذا:

لكن الشفرة تعمل بدونها

نعم هذا صحيح. يمكن استدعاء هذه الوظائف المنفصلة من برنامج نصي مضمّن غير موجود داخل دالة main() . إذا كنت معتادًا (كما هو الحال في المراحل التعليمية المبكرة من البرمجة) لإنشاء برامج نصية مضمنة تعمل تمامًا على ما تحتاجه ، وستحاول معرفة ذلك مرة أخرى إذا احتجت هذه العملية مرة أخرى .. حسنًا ، أنت لست معتادًا على هذا النوع من البنية الداخلية على شفرتك ، لأنه أكثر تعقيدًا للبناء وليس بديهيًا للقراءة.

ولكن هذا هو السيناريو الذي ربما لا يمكن أن تستدعي وظائفه خارجيا ، لأنه إذا فعل ذلك فإنه سيبدأ على الفور في حساب وتخصيص المتغيرات. وهناك احتمالات إذا كنت تحاول إعادة استخدام وظيفة ، فالنص الجديد الخاص بك يرتبط ارتباطًا وثيقًا بالبرنامج القديم بأنه ستكون هناك متغيرات متضاربة.

في تقسيم الوظائف المستقلة ، ستحصل على القدرة على إعادة استخدام عملك السابق عن طريق الاتصال بهم في برنامج نصي آخر. على سبيل المثال ، قد يستورد "example.py" "xy.py" ويستدعي x() ، مع استخدام الدالة "x" من "xy.py". (ربما يتم تكبير الكلمة الثالثة لسلسلة نصية معينة ؛ إنشاء مصفوفة NumPy من قائمة أرقام وتربيعها ؛ أو إلغاء سطح ثلاثي الأبعاد. الاحتمالات لا حدود لها).

(جانباً ، يحتوي هذا السؤال على إجابة من قبلkindall ساعدتني أخيراً في فهمه - لماذا ، وليس كيف. لسوء الحظ تم وضع علامة على أنها نسخة مكررة من هذا السؤال ، والذي أعتقد أنه خطأ).


دعونا ننظر إلى الجواب بطريقة أكثر تجريدًا:

لنفترض أن لدينا هذا الرمز في x.py:

...
<Block A>
if __name__ == '__main__':
    <Block B>
...

يتم تشغيل الكتل A و B عند تشغيل "x.py".

ولكن يتم تشغيل "A" فقط (وليس B) عندما نقوم بتشغيل وحدة نمطية أخرى ، "y.py" على سبيل المثال ، حيث يتم استيراد xy ويتم تشغيل الرمز من هناك (مثل عندما تكون وظيفة في "x.py" اتصل من y.py).


ماذا if __name__ == "__main__": هل؟

__name__ هو متغير عام (في Python ، يعني عالمي بالفعل على مستوى الوحدة النمطية ) موجود في كافة مساحات الأسماء. هو عادة اسم الوحدة (كنوع str ).

كحالة خاصة فقط ، ومع ذلك ، في أي عملية بايثون تقوم بتشغيل ، كما هو الحال في mycode.py:

python mycode.py

يتم تعيين مساحة الاسم العمومية المجهولة بخلاف ذلك إلى قيمة '__main__' إلى __name__ الخاصة __name__ .

وبالتالي ، بما في ذلك الخطوط النهائية

if __name__ == '__main__':
    main()
  • في نهاية البرنامج النصي mycode.py ،
  • عندما تكون الوحدة الأساسية ، نقطة البداية التي يتم تشغيلها بواسطة عملية بايثون ،

سيتسبب في تشغيل الوظيفة الأساسية المحددة بشكل فريد لنص البرنامج النصي الخاص بك.

فائدة أخرى لاستخدام هذا البناء: يمكنك أيضًا استيراد شفرتك كوحدة نمطية في نص برمجي آخر ثم تشغيل الوظيفة الرئيسية إذا قرر برنامجك ووقته:

import mycode
# ... any amount of other code
mycode.main()

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

لكي تكون قصيرًا ، تحتاج إلى معرفة عدة نقاط:

  1. import a يعمل في الواقع كل ما يمكن تشغيله في "أ"

  2. بسبب النقطة 1 ، قد لا ترغب في تشغيل كل شيء في "a" عند استيراده

  3. لحل المشكلة في النقطة 2 ، يسمح لك python بوضع شرط للتحقق

  4. __name__هو متغير ضمني في جميع وحدات. عندما يتم استيراد __name__a.py ، يتم تعيين قيمة a.py على اسم الملف "a" ؛ عند تشغيل a.py مباشرةً باستخدام "python a.py" ، مما يعني أن a.py هي نقطة الإدخال ، ثم يتم تعيين قيمة __name__a.py على سلسلة__main__

  5. بناء على الآلية التي يحدد بها بيثون المتغير __name__لكل وحدة ، هل تعرف كيف تحقق النقطة 3؟ الجواب سهل إلى حد ما ، أليس كذلك؟ وضع إذا كان الشرط: if __name__ == "__main__": .... يمكنك حتى وضع إذا كنت __name__ == "a"تعتمد على حاجتك الوظيفية

الشيء المهم أن الثعبان خاص في النقطة 4! الباقي هو مجرد المنطق الأساسي.


عند تشغيل Python بشكل تفاعلي يتم تعيين متغير __name__ المحلي إلى قيمة __main__ . وبالمثل ، عند تنفيذ وحدة Python من سطر الأوامر ، بدلاً من استيرادها إلى وحدة نمطية أخرى ، يتم تعيين السمة __name__ لها بقيمة __main__ ، بدلاً من الاسم الفعلي للوحدة النمطية. وبهذه الطريقة ، يمكن للوحدات أن تنظر إلى قيمة __name__ الخاصة بهم لتحديد كيفية استخدامهم ، سواءً كدعم لبرنامج آخر أو كتطبيق رئيسي تم تنفيذه من سطر الأوامر. وبالتالي ، فإن اللغة التالية شائعة جدًا في وحدات Python:

if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.

قبل شرح أي شيء حول if __name__ == '__main__' من المهم فهم ما هو __name__ وماذا يفعل.

ما هو __name__ ؟

__name__ هو DunderAlias - يمكن اعتباره متغيرًا عالميًا (يمكن الوصول إليه من الوحدات) ويعمل بطريقة مشابهة global .

هي سلسلة (عالمي كما ذكر أعلاه) كما هو مشار إليه type(__name__) (العائد <class 'str'> ) ، وهو معيار يحمل في ثناياه عوامل لإصدارات Python 3 و Python 2 .

أين:

لا يمكن استخدامه فقط في البرامج النصية ولكن يمكن العثور عليه أيضًا في كل من المترجم والوحدات / الحزم.

مترجم:

>>> print(__name__)
__main__
>>>

النصي:

test_file.py :

print(__name__)

مما __main__ في __main__

الوحدة النمطية أو الحزمة:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

مما somefile في بعض somefile

لاحظ أنه عند استخدامها في حزمة أو وحدة نمطية ، تأخذ __name__ اسم الملف. لا يتم إعطاء مسار الوحدة النمطية أو مسار الحزمة ، ولكن له DunderAlias __file__ الخاص به ، والذي يسمح بذلك.

يجب أن ترى ذلك ، حيث __name__ ، حيث __name__ الملف الرئيسي (أو البرنامج) دائمًا __main__ ، وإذا كانت وحدة / حزمة ، أو أي شيء يتم تشغيله من خلال برنامج نصي آخر لـ Python ، فسيتم إرجاع اسم الملف حيث نشأت من.

ممارسة:

يعني المتغير أنه يمكن الكتابة فوق القيمة ("لا" تعني "يجب") ، يؤدي الكتابة فوق قيمة __name__ إلى نقص في إمكانية القراءة. لذلك لا تفعل ذلك ، لأي سبب من الأسباب. إذا كنت بحاجة إلى متغير ، قم بتعريف متغير جديد.

من المفترض دائمًا أن تكون قيمة __name__ لتكون __main__ أو اسم الملف. مرة أخرى ، سيؤدي تغيير هذه القيمة الافتراضية إلى المزيد من الارتباك في أنها ستفعل شيئًا جيدًا ، مما يتسبب في المزيد من المشكلات أسفل الخط.

مثال:

>>> __name__ = 'Horrify' # Change default from __main__
>>> if __name__ == 'Horrify': print(__name__)
...
>>> else: print('Not Horrify')
...
Horrify
>>>

يعتبر ممارسة جيدة بشكل عام لتشمل if __name__ == '__main__' في البرامج النصية.

الآن للرد if __name__ == '__main__' :

الآن نعرف أن سلوك الأشياء __name__ أصبح أكثر وضوحًا:

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

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

إذا كانت __name__ بالفعل تأخذ قيمة __main__ فسيتم تنفيذ أي شيء في كتلة الكود هذا.

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

وحدات:

يمكن أيضًا استخدام __name__ في الوحدات النمطية لتعريف اسم الوحدة

المتغيرات:

من الممكن أيضًا القيام بأشياء أخرى أقل شيوعًا ولكنها مفيدة مع __name__ ، وسوف أقوم __name__ هنا:

تنفيذ فقط إذا كان الملف وحدة أو حزمة:

if __name__ != '__main__':
    # Do some useful things 

تشغيل شرط واحد إذا كان الملف الرئيسي والآخر إذا لم يكن:

if __name__ == '__main__':
    # Execute something
else:
    # Do some useful things

يمكنك أيضًا استخدامه لتوفير وظائف مساعدة / أدوات مساعدة قابلة للتشغيل على الحزم والوحدات النمطية دون الاستخدام المتقن للمكتبات.

كما يسمح أيضًا بتشغيل الوحدات من سطر الأوامر كنصوص رئيسية ، والتي يمكن أن تكون مفيدة جدًا أيضًا.


السبب ل

if __name__ == "__main__":
    main()

هو في المقام الأول لتجنب مشاكل قفل الاستيراد التي قد تنشأ من وجود كود مستورد مباشرة . تريد أن يتم تشغيل main() إذا تم استدعاء الملف الخاص بك مباشرةً (وهي حالة __name__ == "__main__" ) ، ولكن إذا تم استيراد الرمز الخاص بك ، فيجب على المستورد إدخال __name__ == "__main__" من الوحدة الرئيسية الحقيقية لتجنب مشاكل قفل الاستيراد.

التأثير الجانبي هو أنك تقوم بتسجيل الدخول تلقائيًا إلى منهجية تدعم نقاط دخول متعددة. يمكنك تشغيل البرنامج باستخدام main() كنقطة دخول ، ولكن لا يلزمك ذلك . بينما يتوقع setup.py main() ، فإن الأدوات الأخرى تستخدم نقاط إدخال بديلة. على سبيل المثال ، لتشغيل ملفك كعملية gunicorn ، تقوم بتعريف وظيفة app() بدلاً من main() . تمامًا كما هو الحال مع gunicorn ، تستورد gunicorn شفرتك بحيث لا تريد أن تفعل أي شيء أثناء استيرادها (بسبب مشكلة قفل الاستيراد).


عندما يتم تشغيل البرنامج النصي الخاص بك عن طريق تمريره كمترجم لمترجم Python ،

python myscript.py

يتم تنفيذ كافة التعليمات البرمجية الموجودة على مستوى المسافة البادئة 0. يتم تعريف الوظائف والدروس التي يتم تعريفها جيدًا ، ولكن لا يتم تشغيل أي منها. بخلاف اللغات الأخرى ، لا توجد وظيفة main() يتم تشغيلها تلقائيًا - تكون الدالة main() ضمنيًا جميع التعليمات البرمجية في المستوى الأعلى.

في هذه الحالة ، يكون رمز المستوى الأعلى كتلة if . __name__ هو __name__ يتم تقييمه إلى اسم الوحدة الحالية. ومع ذلك ، إذا تم تشغيل وحدة نمطية مباشرة (كما هو الحال في myscript.py أعلاه) ، فعندئذٍ يتم تعيين __name__ بدلاً من ذلك على السلسلة "__main__" . وبالتالي ، يمكنك اختبار ما إذا كان يتم تشغيل البرنامج النصي مباشرة أو يتم استيراده بواسطة شيء آخر عن طريق الاختبار

if __name__ == "__main__":
    ...

إذا تم استيراد النص البرمجي الخاص بك إلى وحدة أخرى ، فسيتم استيراد التعريفات المختلفة للفئة والدالة وسيتم تنفيذ التعليمات البرمجية ذات المستوى الأعلى ، ولكن لن يتم تشغيل الشفرة في نص ذلك الشرط if الشرط أعلاه في هذه الحالة لم يتم الوفاء بها. كمثال أساسي ، ضع في اعتبارك النصين التاليين:

# file one.py
def func():
    print("func() in one.py")

print("top-level in one.py")

if __name__ == "__main__":
    print("one.py is being run directly")
else:
    print("one.py is being imported into another module")
# file two.py
import one

print("top-level in two.py")
one.func()

if __name__ == "__main__":
    print("two.py is being run directly")
else:
    print("two.py is being imported into another module")

الآن ، إذا قمت باستدعاء مترجم باسم

python one.py

سيكون الناتج

top-level in one.py
one.py is being run directly

إذا قمت بتشغيل two.py بدلاً من ذلك:

python two.py

لقد حصلت

top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly

وبالتالي ، عندما يتم تحميل الوحدة one ، تساوي __name__ "one" بدلاً من "__main__" .


جميع الأجوبة شرحت الوظيفة إلى حد كبير. لكنني سأقدم مثالاً على استخدامها قد يساعد في إزالة المفهوم أكثر.

افترض أن لديك اثنين من ملفات Python ، وهما a.py و b.py. الآن ، تستورد a.py b.py. قمنا بتشغيل ملف a.py ، حيث يتم تنفيذ شفرة "import b.py" أولاً. قبل تشغيل باقي شفرة a.py ، يجب تشغيل الشفرة الموجودة في الملف b.py تمامًا.

في شفرة b.py ، هناك شفرة معينة حصرية لهذا الملف b.py ولا نريد أي ملف آخر (بخلاف ملف b.py) ، الذي قام باستيراد ملف b.py ، لتشغيله.

هذا هو ما يتحقق هذا السطر من التعليمات البرمجية. إذا كان هو الملف الرئيسي (أي b.py) الذي يقوم بتشغيل الكود ، وهو في هذه الحالة ليس (يتم تشغيل الملف الرئيسي) ، فلن يتم تنفيذ الكود إلا.


if __name__ == "__main__" هو الجزء الذي يتم تشغيله عند تشغيل البرنامج النصي من (قل) سطر الأوامر باستخدام أمر مثل python myscript.py .


هذه الإجابة هي لمبرمجي جافا تعلم بايثون. يحتوي كل ملف جافا عادة على فصل دراسي واحد. يمكنك استخدام هذا الفصل بطريقتين:

  1. اتصل بالصف من ملفات أخرى. عليك فقط استيراده في برنامج الاتصال.

  2. قم بتشغيل الفصل الدراسي بمفرده ، لأغراض الاختبار.

بالنسبة للحالة الأخيرة ، يجب أن تحتوي الطبقة على طريقة main () ثابتة عامة. في بيثون يتم تقديم هذا الغرض من قبل العلامة المحددة عالميا '__main__'.


if __name__ == "__main__": هي في الأساس بيئة البرنامج النصي ذات المستوى الأعلى ، وهي تحدد المترجم ("لدي الأولوية القصوى التي يجب تنفيذها أولاً").

'__main__' هو اسم النطاق الذي يتم فيه تنفيذ التعليمة البرمجية ذات المستوى الأعلى. يتم ضبط __name__ للوحدة النمطية على '__main__' عند القراءة من الإدخال القياسي أو البرنامج النصي أو من موجه تفاعلي.

if __name__ == "__main__":
    # Execute only if run as a script
    main()

أعتقد أنه من الأفضل كسر الإجابة بعمق وبعبارات بسيطة:

__name__ : كل ​​وحدة في Python لها خاصية خاصة تسمى __name__ . وهو متغير مضمّن يقوم بإرجاع اسم الوحدة النمطية.

__main__ : مثل لغات البرمجة الأخرى ، بيثون لديها نقطة دخول تنفيذية ، أي main. '__main__' هو اسم النطاق الذي يتم فيه تنفيذ التعليمة البرمجية ذات المستوى الأعلى . بشكل أساسي ، لديك طريقتان لاستخدام وحدة Python: قم بتشغيلها مباشرة كبرنامج نصي ، أو قم باستيرادها. عندما يتم تشغيل وحدة نمطية كبرنامج نصي ، يتم تعيين __main__ إلى __main__ .

وبالتالي ، يتم تعيين قيمة السمة __name__ إلى __main__ عند تشغيل الوحدة النمطية كبرنامج رئيسي. وإلا يتم تعيين قيمة __name__ على اسم الوحدة النمطية.


يعتبر:

if __name__ == "__main__":
    main()

يتحقق ما إذا كانت السمة __name__ للبرنامج النصي Python هي "__main__" . وبعبارة أخرى ، إذا تم تنفيذ البرنامج نفسه ، فإن السمة ستكون __main__ ، لذلك سيتم تنفيذ البرنامج (في هذه الحالة الدالة main() ).

ومع ذلك ، إذا تم استخدام نص برمجي Python من قِبل وحدة نمطية ، فسيتم تنفيذ أي كود خارج بيان if ، لذلك if \__name__ == "\__main__" فقط للتحقق مما إذا كان البرنامج يستخدم كوحدة نمطية أم لا ، و لذلك تقرر ما إذا كان سيتم تشغيل التعليمات البرمجية.


ببساطة ، __name__ هو متغير يتم تعريفه لكل نص برمجي يحدد ما إذا كان البرنامج النصي يتم تشغيله كوحدة نمطية رئيسية أو يتم تشغيله كوحدة نمطية مستوردة.

إذا كان لدينا نصان

#script1.py
print "Script 1's name: {}".format(__name__)

و

#script2.py
import script1
print "Script 2's name: {}".format(__name__)

الإخراج من تنفيذ script1 هو

Script 1's name: __main__

والإخراج من تنفيذ script2 هو:

Script1's name is script1
Script 2's name: __main__

كما ترون ، يخبرنا __name__ ما هي الكود "الوحدة الرئيسية". هذا أمر رائع ، لأنه يمكنك كتابة التعليمات البرمجية فقط ولا داعي للقلق بشأن المشكلات الهيكلية مثل C / C ++ ، حيث ، إذا كان الملف لا ينفذ وظيفة "رئيسية" ، فلا يمكن تجميعه كملف قابل للتنفيذ ، وإذا كان كذلك ، لا يمكن استخدامه بعد ذلك كمكتبة.

لنفترض أنك كتبت نصًا برمجيًا في Python ينفّذ شيئًا رائعًا وتنفذ حمولة من الوظائف المفيدة لأغراض أخرى. إذا كنت ترغب في استخدامها ، if __name__ == "__main__": استيراد البرنامج النصي الخاص بك واستخدامه بدون تنفيذ البرنامج (نظراً لأن التعليمات البرمجية الخاصة بك لا تنفذ إلا في if __name__ == "__main__": context). في حين أنه في C / C ++ سيكون عليك تقسيم هذه الأجزاء إلى وحدة منفصلة تتضمن الملف. صورة الوضع أدناه ؛

الأسهم عبارة عن روابط استيراد. بالنسبة لثلاث وحدات ، كل محاولة لتضمين كود الوحدات السابقة هناك ستة ملفات (تسعة ، عد ملفات التنفيذ) وخمسة روابط. هذا يجعل من الصعب تضمين تعليمات برمجية أخرى في مشروع C إلا إذا تم تجميعها على وجه التحديد كمكتبة. الآن تصويرها لبيثون:

تكتب وحدة نمطية ، وإذا أراد شخص ما استخدام شفرتك ، فإنه يقوم فقط باستيرادها ، ويمكن أن يساعد المتغير __name__ على فصل الجزء القابل للتنفيذ من البرنامج من جزء المكتبة.


في الآونة الأخيرة ، صادفت هذا أثناء إنشاء فصل في python (التعلم العميق) ولفهمي والاتفاق على التفسيرات المدرجة أعلاه ، سأوضح

__name__=="__main__"

في بعض الأحيان نقوم ببناء صف في ملف .py ، ونحدد الكثير من الوظائف داخل تلك الفئة. ولكننا لا نرغب في معالجة كل وظائف الصف هذه لغرض واحد. forexample ، لإنشاء فئة وتعريف بعض الوظائف لإنشاء البيانات (ملفات .npy) بينما بعضها لتحميل البيانات. لذلك إذا عرفنا

__name__=="__main__"

XXX = CLASS_NAME ()

xxx.create_data ()

يعني إذا اتصلنا بالملف .py ، فسيعمل على إنشاء البيانات فقط ولن يقوم بمعالجة وظائف الصف الأخرى. يمكن أيضًا استيراد وظائف الصف الأخرى (تحميل البيانات) بواسطة فئات أخرى.


أنشئ ملفًا ، a.py :

print(__name__) # It will print out __main__

__name__يساوي دائمًا __main__متى يتم تشغيل هذا الملف مباشرةً لإظهار أن هذا هو الملف الرئيسي.

قم بإنشاء ملف آخر ، b.py ، في نفس الدليل:

import a  # Prints a

شغلها. وسوف طباعة و ، أي اسم الملف الذي يتم استيراده .

لذلك ، لعرض سلوكين مختلفين للملف نفسه ، هذه خدعة شائعة الاستخدام:

# Code to be run when imported into another python file

if __name__ == '__main__':
    # Code to be run only when run directly

عندما يقرأ مترجم Python ملف مصدر ، فإنه ينفذ جميع التعليمات البرمجية الموجودة فيه.

قبل تنفيذ الشفرة ، سيحدد بعض المتغيرات الخاصة. على سبيل المثال ، إذا كان مترجم Python يقوم بتشغيل تلك الوحدة (الملف المصدر) كبرنامج رئيسي ، فإنه يقوم بتعيين المتغير __name__ الخاص __name__ له قيمة "__main__" . في حالة استيراد هذا الملف من وحدة نمطية أخرى ، سيتم تعيين __name__ إلى اسم الوحدة النمطية.

في حالة البرنامج النصي الخاص بك ، دعونا نفترض أنه ينفذ كوظيفة رئيسية ، على سبيل المثال قلت شيئا مثل

python threading_example.py

على سطر الأوامر. بعد إعداد المتغيرات الخاصة ، سيتم تنفيذ جملة import وتحميل تلك الوحدات. سيقوم بعد ذلك بتقييم كتلة def ، وإنشاء كائن دالة وإنشاء متغير يسمى myfunction يشير إلى كائن الدالة. ستقرأ بعد ذلك العبارة if وسترى أن __name__ تساوي "__main__" ، لذا سيتم تنفيذ الكتلة الظاهرة هناك.

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

انظر هذه الصفحة للحصول على بعض التفاصيل الإضافية.

ملاحظة (بواسطة Stainsor): إذا قمت بوضع التعليمة البرمجية قبل تعريفات الدالة ، فسوف يتم تنفيذها قبل main.

print("This code executes before main.") 

def functionA():
    print("Function A")

def functionB():
    print("Function B")

if __name__ == '__main__':
    functionA()
    functionB()

إذا كانت هذه الوحدة الرئيسية في الواقع ، فإن هذا الرمز ينتج عنه:

This code executes before main. 
Function A 
Function B

إذا كانت هذه الوحدة غير رئيسية ، فستحصل على:

This code executes before main. 

أبسط تفسير للمتغير __name__ ( __name__ ) هو ما يلي:

قم بإنشاء الملفات التالية.

# a.py
import b

و

# b.py
print "Hello World from %s!" % __name__

if __name__ == '__main__':
    print "Hello World again from %s!" % __name__

سيؤدي تشغيلها إلى الحصول على هذا الناتج:

$ python a.py
Hello World from b!

كما ترى ، عندما يتم استيراد وحدة ، تعيّن بايثون globals()['__name__'] في هذه الوحدة إلى اسم الوحدة.

$ python b.py
Hello World from __main__!
Hello World again from __main__!

كما ترى ، عند تنفيذ ملف ما ، تقوم بايثون بتعيين globals()['__name__'] في هذا الملف إلى "__main__" .


typeهو في الواقع metaclass- فئة يخلق فصول أخرى. معظمها metaclassهي الفئات الفرعية من type. و metaclassيتلقى newالدرجة الأولى كما حجتها وتوفير إمكانية الوصول إلى كائن الفئة مع التفاصيل المذكورة على النحو التالي:

>>> class MetaClass(type):
...     def __init__(cls, name, bases, attrs):
...         print ('class name: %s' %name )
...         print ('Defining class %s' %cls)
...         print('Bases %s: ' %bases)
...         print('Attributes')
...         for (name, value) in attrs.items():
...             print ('%s :%r' %(name, value))
... 

>>> class NewClass(object, metaclass=MetaClass):
...    get_choch='dairy'
... 
class name: NewClass
Bases <class 'object'>: 
Defining class <class 'NewClass'>
get_choch :'dairy'
__module__ :'builtins'
__qualname__ :'NewClass'

Note:

لاحظ أنه لم يتم إنشاء فئة في أي وقت؛ فعل بسيط من خلق الطبقة التي أدت إلى تنفيذ metaclass.







python namespaces main python-module idioms