تعلم لغة البايثون – الدرس الثاني عشر الوحدات والحزم في بايثون Python Modules and Packages

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

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

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

mygame/
mygame/game.py
mygame/draw.py

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

يتم استيراد الوحدات النمطية من وحدات نمطية أخرى باستخدام الأمر import. في هذا المثال ، قد يبدو البرنامج النصي game.py شيئًا مثل هذا

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

def play_game():
    ...

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

# هذا يعني أنه إذا تم تنفيذ هذا البرنامج النصي ، ثم
سيتم تنفيذ # main ()
if __name__ == '__main__':
    main()

قد تبدو وحدة الرسم على النحو التالي:

# draw.py

def draw_game():
    ...

def clear_screen(screen):
    ...

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

عندما يتم تشغيل توجيه الاستيراد ، سيبحث مترجم Python عن ملف في الدليل الذي تم تنفيذ البرنامج النصي منه ، باسم الوحدة مع بادئة .py ، لذا في حالتنا سيحاول البحث عن الرسم. السنة التحضيرية. إذا وجدت واحدة ، سيتم استيرادها. إذا لم يكن كذلك ، فسيستمر في البحث عن الوحدات المدمجة.

ربما لاحظت أنه عند استيراد وحدة نمطية ، يظهر ملف .pyc ، وهو ملف Python مترجم. تقوم Python بتجميع الملفات في Python bytecode حتى لا تضطر إلى تحليل الملفات في كل مرة يتم فيها تحميل الوحدات النمطية. في حالة وجود ملف .pyc ، يتم تحميله بدلاً من ملف .py ، ولكن هذه العملية شفافة للمستخدم.

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

قد نقوم أيضًا باستيراد الوظيفة draw_game مباشرة في مساحة اسم البرنامج النصي الرئيسي ، باستخدام الأمر from.

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

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

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

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

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

يجوز لنا أيضًا استخدام الأمر import * لاستيراد جميع الكائنات من وحدة نمطية معينة ، مثل هذا:

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

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

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

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

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

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

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

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

تهيئة الوحدة

في المرة الأولى التي يتم فيها تحميل الوحدة النمطية في نص Python النصي ، يتم تهيئتها من خلال تنفيذ التعليمات البرمجية في الوحدة النمطية مرة واحدة. إذا قامت وحدة نمطية أخرى في الكود الخاص بك باستيراد نفس الوحدة النمطية مرة أخرى ، فلن يتم تحميلها مرتين ولكن مرة واحدة فقط – لذا تعمل المتغيرات المحلية داخل الوحدة النمطية كـ “مفرد” – يتم تهيئتها مرة واحدة فقط.

من المفيد معرفة ذلك ، لأن هذا يعني أنه يمكنك الاعتماد على هذا السلوك لتهيئة الكائنات. فمثلا:

# draw.py

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

def clear_screen(screen):
    ...

class Screen():
    ...

# تهيئة main_screen باعتبارها قائمة فردية
main_screen = Screen()

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

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

PYTHONPATH=/foo python game.py

سيؤدي ذلك إلى تنفيذ game.py وسيمكن البرنامج النصي من تحميل الوحدات النمطية من دليل foo وكذلك الدليل المحلي.

طريقة أخرى هي دالة sys.path.append. يمكنك تنفيذ ذلك قبل تشغيل أمر الاستيراد:

sys.path.append("/foo")

سيؤدي ذلك إلى إضافة دليل foo إلى قائمة المسارات للبحث عن الوحدات النمطية أيضًا.

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

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

هناك وظيفتان مهمتان للغاية في متناول اليد عند استكشاف الوحدات النمطية في Python – وظائف dir و help.

إذا أردنا استيراد urllib للوحدة النمطية ، والتي تمكننا من إنشاء بيانات قراءة من عناوين URL ، فإننا ببساطة نستورد الوحدة:

# استيراد المكتبة
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']

سنحصل على النتيجة التالية عند التشغيل

Out[1]: 
['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']

عندما نجد الوظيفة في الوحدة التي نريد استخدامها ، يمكننا أن نقرأ عنها أكثر باستخدام وظيفة المساعدة ، داخل مترجم Python

help(urllib.urlopen)

حزم الكتابة

الحزم هي مساحات أسماء تحتوي على حزم ووحدات نمطية متعددة. إنها مجرد أدلة ، ولكن مع تطور.

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

إذا قمنا بإنشاء دليل يسمى foo ، والذي يمثل اسم الحزمة ، فيمكننا بعد ذلك إنشاء وحدة نمطية داخل تلك الحزمة تسمى bar. يجب أيضًا ألا ننسى إضافة ملف init.py داخل دليل foo.

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

import foo.bar

او:

from foo import bar

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

يمكن لملف init.py أيضًا تحديد الوحدات التي تصدرها الحزمة كواجهة برمجة تطبيقات ، مع الاحتفاظ بالوحدات الأخرى الداخلية ، عن طريق تجاوز المتغير all ، كما يلي:

__init__.py:

__all__ = ["bar"]

تمرين

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

import re

# رمزك هنا

الحل

import re

# رمزك هنا
find_members = []
for member in dir(re):
    if "find" in member:
        find_members.append(member)

print(sorted(find_members))

سنحصل على النتيجة التالية عند التشغيل

<script.py> output:
    ['findall', 'finditer']





Leave a Reply