Get started learning Python with DataCamp's free Intro to Python tutorial. Learn Data Science by completing interactive coding challenges and watching videos by expert instructors. Start Now!

This site is generously supported by DataCamp. DataCamp offers online interactive Python Tutorials for Data Science. Join 11 million other learners and get started learning Python for data science today!

Good news! You can save 25% off your Datacamp annual subscription with the code LEARNPYTHON23ALE25 - Click here to redeem your discount

الوحدات والحزم


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

كتابة الوحدات

الوحدات في بايثون هي فقط ملفات بايثون بامتداد .py. اسم الوحدة هو نفس اسم الملف. يمكن لوحدة بايثون أن تحتوي على مجموعة من الدوال، أو الفئات، أو المتغيرات المعرفة والمطبقة. المثال السابق يشمل ملفين:

mygame/

  • mygame/game.py

  • mygame/draw.py

تنفذ سكربت بايثون game.py اللعبة. يستخدم الدالة draw_game من الملف draw.py، أو بعبارة أخرى، الوحدة draw التي تطبق المنطق الخاص برسم اللعبة على الشاشة.

يتم استيراد الوحدات من وحدات أخرى باستخدام الأمر import. في هذا المثال، قد يبدو السكربت game.py كما يلي:

# game.py
# استيراد وحدة الرسم
import draw

def play_game():
    ...

def main():
    result = play_game()
    draw.draw_game(result)

# هذا يعني أنه إذا تم تنفيذ هذا السكربت، سيتم تنفيذ الدالة الرئيسية
if __name__ == '__main__':
    main()

قد تبدو وحدة draw كما يلي:

# draw.py

def draw_game():
    ...

def clear_screen(screen):
    ...

في هذا المثال، تستورد وحدة game وحدة draw، مما يتيح لها استخدام الدوال المطبقة في تلك الوحدة. تستخدم الدالة main الدالة المحلية play_game لتشغيل اللعبة، ثم ترسم نتيجة اللعبة باستخدام دالة مطبقة في وحدة draw تسمى draw_game. لاستخدام الدالة draw_game من وحدة draw, نحتاج إلى تحديد الوحدة التي تم تنفيذ الدالة فيها باستخدام النقطة ".". للإشارة إلى الدالة draw_game من وحدة game, نحتاج إلى استيراد وحدة draw ثم نستدعي draw.draw_game().

عند تشغيل توجيه import draw, يبحث مفسر بايثون عن ملف في الدليل الذي نُفذ فيه التركيبي مع اسم الوحدة واللاحقة .py. في هذه الحالة سيبحث عن draw.py. إذا تم العثور عليها، سيتم استيرادها. إذا لم يتم العثور عليها، سيواصل البحث عن الوحدات المدمجة.

ربما لاحظت أنه عند استيراد وحدة، يتم إنشاء ملف .pyc. هذا هو ملف بايثون تم تجميعه. يجمع بايثون الملفات إلى بايت كود لتجنب تفسير الملفات في كل مرة يتم فيها تحميل الوحدات. إذا وجد ملف .pyc, يتم تحميله بدلاً من ملف .py. هذه العملية شفافة للمستخدم.

استيراد الكائنات من الوحدات إلى نطاق الأسماء الحالي

نطاق الأسماء هو نظام يتم فيه تسمية كل كائن ويمكن الوصول إليه في بايثون. نستورد الدالة draw_game إلى نطاق أسماء السكربت الرئيسي باستخدام الأمر from.

# game.py
# استيراد وحدة الرسم
from draw import draw_game

def main():
    result = play_game()
    draw_game(result)

ربما لاحظت في هذا المثال أن اسم الوحدة لا يسبق draw_game, لأننا حددنا اسم الوحدة باستخدام الأمر import.

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

استيراد كل الكائنات من وحدة

يمكنك استخدام الأمر import * لاستيراد جميع الكائنات في وحدة كما يلي:

# game.py
# استيراد وحدة الرسم
from draw import *

def main():
    result = play_game()
    draw_game(result)

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

اسم استيراد مخصص

يمكن تحميل الوحدات تحت أي اسم تريده. هذا مفيد عند استيراد وحدة بشكل شرطي لاستخدام نفس الاسم في باقي الشيفرة.

على سبيل المثال، إذا كان لديك وحدتين draw بأسماء مختلفة قليلاً، يمكنك القيام بما يلي:

# game.py
# استيراد وحدة الرسم
if visual_mode:
    # في الوضع البصري، نرسم باستخدام الرسومات
    import draw_visual as draw
else:
    # في الوضع النصي، نطبع النص
    import draw_textual as draw

def main():
    result = play_game()
    # يمكن أن يكون هذا إما بصري أو نصي اعتمادًا على visual_mode
    draw.draw_game(result)

تهيئة الوحدة

أول مرة يتم فيها تحميل وحدة إلى سكربت بايثون قيد التشغيل، يتم تهيئتها عن طريق تنفيذ الكود في الوحدة مرة واحدة. إذا استوردت وحدة أخرى في شيفرتك نفس الوحدة مرة أخرى، فلن يتم تحميلها مرة أخرى، بحيث تعمل المتغيرات المحلية داخل الوحدة كـ "singleton"، مما يعني أنه يتم تهيئتها مرة واحدة فقط.

يمكنك بعد ذلك استخدام هذا لتهيئة الكائنات. على سبيل المثال:

# draw.py

def draw_game():
    # عند مسح الشاشة يمكننا استخدام كائن الشاشة الرئيسي المهيئ في هذه الوحدة
    clear_screen(main_screen)
    ...

def clear_screen(screen):
    ...

class Screen():
    ...

# تهيئة main_screen كـ singleton
main_screen = Screen()

توسيع مسار تحميل الوحدات

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

PYTHONPATH=/foo python game.py

هذا ينفذ game.py, ويُمكّن السكربت من تحميل الوحدات من دليل foo, بالإضافة إلى الدليل المحلي.

يمكنك أيضًا استخدام وظيفة sys.path.append. نفذها قبل تشغيل الأمر import:

sys.path.append("/foo")

الآن تمت إضافة دليل foo إلى قائمة المسارات التي يتم البحث فيها عن الوحدات.

استكشاف الوحدات المدمجة

تحقق من القائمة الكاملة للوحدات المضمنة في مكتبة بايثون القياسية هنا.

وظيفتان مهمتان جدًا تكونان مفيدتين عند استكشاف الوحدات في بايثون - وظيفتا dir و help.

لاستيراد الوحدة urllib, التي تمكننا من قراءة البيانات من عناوين URL, نقوم import للوحدة:

# استيراد المكتبة
import urllib

# استخدامها
urllib.urlopen(...)

يمكننا البحث عن الدوال المطبقة في كل وحدة باستخدام وظيفة dir:

>>> import urllib
>>> dir(urllib)
['ContentTooShortError', 'FancyURLopener', 'MAXFTPCACHE', 'URLopener', '__all__', '__builtins__', 
'__doc__', '__file__', '__name__', '__package__', '__version__', '_ftperrors', '_get_proxies', 
'_get_proxy_settings', '_have_ssl', '_hexdig', '_hextochr', '_hostprog', '_is_unicode', '_localhost', 
'_noheaders', '_nportprog', '_passwdprog', '_portprog', '_queryprog', '_safe_map', '_safe_quoters', 
'_tagprog', '_thishost', '_typeprog', '_urlopener', '_userprog', '_valueprog', 'addbase', 'addclosehook', 
'addinfo', 'addinfourl', 'always_safe', 'basejoin', 'c', 'ftpcache', 'ftperrors', 'ftpwrapper', 'getproxies', 
'getproxies_environment', 'getproxies_macosx_sysconf', 'i', 'localhost', 'main', 'noheaders', 'os', 
'pathname2url', 'proxy_bypass', 'proxy_bypass_environment', 'proxy_bypass_macosx_sysconf', 'quote', 
'quote_plus', 'reporthook', 'socket', 'splitattr', 'splithost', 'splitnport', 'splitpasswd', 'splitport', 
'splitquery', 'splittag', 'splittype', 'splituser', 'splitvalue', 'ssl', 'string', 'sys', 'test', 'test1', 
'thishost', 'time', 'toBytes', 'unquote', 'unquote_plus', 'unwrap', 'url2pathname', 'urlcleanup', 'urlencode', 
'urlopen', 'urlretrieve']

عندما نجد الدالة في الوحدة التي نريد استخدامها، يمكننا قراءة المزيد عنها باستخدام وظيفة help, باستخدام مفسر بايثون:

help(urllib.urlopen)

كتابة الحزم

الحزم هي نطاقات تحتوي على مجموعات متعددة من الحزم والوحدات. إنها فقط أدلة، ولكن مع بعض المتطلبات.

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

إذا قمنا بإنشاء دليل يسمى foo, الذي يُشير إلى اسم الحزمة، يمكننا بعد ذلك إنشاء وحدة داخل تلك الحزمة تسمى bar. ثم نضيف ملف __init__.py داخل دليل foo.

لاستخدام الوحدة bar, يمكننا استيرادها بطريقتين:

import foo.bar

أو:

from foo import bar

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

ملف __init__.py يمكنه أيضًا تحديد الوحدات التي تصدرها الحزمة كواجهة برمجية، مع إبقاء وحدات أخرى داخلية، عن طريق تجاوز المتغير __all__ هكذا:

__init__.py:

__all__ = ["bar"]

Exercise

في هذا التمرين، اطبع قائمة مرتبة أبجديًا بجميع الدوال في وحدة re التي تحتوي على الكلمة find.

import re # Your code goes here find_members = [] import re # Your code goes here find_members = [] for member in dir(re): if "find" in member: find_members.append(member) print(sorted(find_members)) test_object('find_members') success_msg('Great work!')

This site is generously supported by DataCamp. DataCamp offers online interactive Python Tutorials for Data Science. Join over a million other learners and get started learning Python for data science today!

Previous Tutorial Next Tutorial Take the Test
Copyright © learnpython.org. Read our Terms of Use and Privacy Policy