التنبيهات التالية ظهرت :
Warning [2] Undefined array key "lockoutexpiry" - Line: 94 - File: global.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php 94 errorHandler->error
/showthread.php 28 require_once
Warning [2] Undefined property: MyLanguage::$today_rel - Line: 474 - File: inc/functions.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions.php 474 errorHandler->error
/global.php 489 my_date
/showthread.php 28 require_once
Warning [2] Undefined array key "lockoutexpiry" - Line: 573 - File: global.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php 573 errorHandler->error
/showthread.php 28 require_once
Warning [2] Undefined variable $can_access_moderationqueue - Line: 749 - File: global.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php 749 errorHandler->error
/showthread.php 28 require_once
Warning [2] Undefined array key "avatartype" - Line: 889 - File: global.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php 889 errorHandler->error
/showthread.php 28 require_once
Warning [2] Undefined array key "avatartype" - Line: 889 - File: global.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php 889 errorHandler->error
/showthread.php 28 require_once
Warning [2] Undefined variable $awaitingusers - Line: 34 - File: global.php(956) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php(956) : eval()'d code 34 errorHandler->error
/global.php 956 eval
/showthread.php 28 require_once
Warning [2] Undefined array key "style" - Line: 1021 - File: global.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php 1021 errorHandler->error
/showthread.php 28 require_once
Warning [2] Undefined property: MyLanguage::$lang_select_default - Line: 5196 - File: inc/functions.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions.php 5196 errorHandler->error
/global.php 1021 build_theme_select
/showthread.php 28 require_once
Warning [2] Undefined array key "additionalgroups" - Line: 7360 - File: inc/functions.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions.php 7360 errorHandler->error
/inc/functions.php 5216 is_member
/global.php 1021 build_theme_select
/showthread.php 28 require_once
Warning [2] Undefined property: MyLanguage::$bottomlinks_forumteam - Line: 2 - File: global.php(1033) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php(1033) : eval()'d code 2 errorHandler->error
/global.php 1033 eval
/showthread.php 28 require_once
Warning [2] Undefined property: MyLanguage::$bottomlinks_markread - Line: 15 - File: global.php(1056) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/global.php(1056) : eval()'d code 15 errorHandler->error
/global.php 1056 eval
/showthread.php 28 require_once
Warning [2] Undefined array key "mybb" - Line: 1997 - File: inc/functions.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions.php 1997 errorHandler->error
/inc/functions_indicators.php 41 my_set_array_cookie
/showthread.php 669 mark_thread_read
Warning [2] Undefined property: MyLanguage::$ratings_update_error - Line: 5 - File: showthread.php(772) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/showthread.php(772) : eval()'d code 5 errorHandler->error
/showthread.php 772 eval
Warning [2] Undefined array key "additionalgroups" - Line: 7360 - File: inc/functions.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions.php 7360 errorHandler->error
/inc/functions_user.php 816 is_member
/inc/functions_post.php 416 purgespammer_show
/showthread.php 1124 build_postbit
Warning [2] Undefined array key "profilefield" - Line: 6 - File: inc/functions_post.php(484) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions_post.php(484) : eval()'d code 6 errorHandler->error
/inc/functions_post.php 484 eval
/showthread.php 1124 build_postbit
Warning [2] Undefined array key "canonlyreplyownthreads" - Line: 672 - File: inc/functions_post.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions_post.php 672 errorHandler->error
/showthread.php 1124 build_postbit
Warning [2] Undefined array key "showimages" - Line: 758 - File: inc/functions_post.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions_post.php 758 errorHandler->error
/showthread.php 1124 build_postbit
Warning [2] Undefined array key "showvideos" - Line: 763 - File: inc/functions_post.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/inc/functions_post.php 763 errorHandler->error
/showthread.php 1124 build_postbit
Warning [2] Undefined array key "invisible" - Line: 1565 - File: showthread.php PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/showthread.php 1565 errorHandler->error
Warning [2] Undefined property: MyLanguage::$post_deleted_error - Line: 21 - File: showthread.php(1597) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/showthread.php(1597) : eval()'d code 21 errorHandler->error
/showthread.php 1597 eval
Warning [2] Undefined variable $threadnotesbox - Line: 33 - File: showthread.php(1597) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/showthread.php(1597) : eval()'d code 33 errorHandler->error
/showthread.php 1597 eval
Warning [2] Undefined variable $addremovesubscription - Line: 82 - File: showthread.php(1597) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/showthread.php(1597) : eval()'d code 82 errorHandler->error
/showthread.php 1597 eval
Warning [2] Undefined variable $thread_deleted - Line: 104 - File: showthread.php(1597) : eval()'d code PHP 8.1.2-1ubuntu2.18 (Linux)
File Line Function
/showthread.php(1597) : eval()'d code 104 errorHandler->error
/showthread.php 1597 eval




تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
مجالات التسمية (namespaces) في بيثون
#1
مجالات التسمية (namespaces) في بيثون

مجال التسمية    =   namespace
نطاق المتغير    =   scope
محلي            =   local
شامل            =   global
وسيط - معطى     =   argument - parameter
فئة             =   class  
دالة            =   function
كتلة            =   block
تعليمة          =   instruction
تعبير           =   expression
سمة             =   attribute
معلمة           =   parameter
مرجع            =   reference
الدوال المتداخلة=   nested functions
لعل مفهوم 'نطاق المتغير' قد اعترضك سابقا، او ربما لاحظت أن متغيرين يحملان نفس الاسم متواجدان في سكربت واحد، أحدهما داخل الوحدة و الآخر داخل دالة مثلا.
نجد في بيثون كما في غالب لغات البرمجة، إن لم يكن كلها، قواعد تحدد نطاق المتغير. المقصود متى وكيف يمكن الوصول الى المتغير؟ ما هي المتغيرات الممكن استخدامها داخل دالة قمنا بتعريفها؟ هل ما قمنا بتمريره اليها كوسيط؟ هل يمكننا اضافة متغيرات داخل الدالة مع امكانية الوصول اليها من خارجها؟
كود :
a = 3
def my_var():
   print("a = {}".format(a))

my_var()                        # a = 3
print(a)                        # 3
- الاستنتاج الاول: يمكننا الوصول الى متغير قمنا بتعريفه خارج الدالة رغم أننا لم نمرره كوسيط. لنحاول تعديله من داخلها:
كود :
a = 3
def my_var():
   a = 5
   print("a = {}".format(a))

my_var()                        # a = 5
print(a)                        # 3
- هنا نستنتج أمرين: الاول هو أننا لا نستطيع تنفيذ تعديل مباشر (أي عبر التعيين بواسطة =) لقيمة متغير وقع تعريفه خارج نطاق الدالة. الاستنتاج الثاني هو أن محاولة تعديل المتغير a داخل الدالة أنتج في الواقع متغيرا آخر بنفس الاسم وما من طريقة مباشرة للوصول اليه من خارج الدالة. سنرى أن تعديل متغيرات معرفة خارج النطاق المحلي ممكن في بعض الاحيان لكن ليس مباشرة (عبر list.append مثلا)

## المتغيرات المحلية (local variables)
يقوم بيثون بالبحث عن مرجع المتغير a في النطاق المحلي للدالة أولا. هذا النطاق يحتوي على الوسائط التي ممرناها للدالة إن وجدت، والمتغيرات التي قمنا بتعريفها داخل الدالة. في المثال الاول أعلاه، اكتشف بيثون أنه لا وجود لمتغير باسم a في النطاق المحلي للدالة، عندها مر للبحث عن a داخل نطاق محلي أشمل حيث تم تعريف الدالة، وهنا وجد a واستخدمها.
في المثال الثاني، وجد بيثون المتغير a في النطاق المحلي للدالة فاستخدمها (a = 5) ، ثم لما طلبنا طباعة a مباشرة، بدأ البحث عنها في النطاق المحلي دائما، لكنه هنا النطاق الذي فيه تعريف الدالة فوجد أن a = 3 .
سنقدم  مزيدا من الامثلة لفهم نطاق المتغيرات أكثر:
كود :
def my_var():
   x = 10
   print("x = {}".format(x))
my_var()                        # x = 10
print(x)                        # Exception: NameError
يظهر لنا هذا المثال بشكل جلي أن المتغير x لم يعد بالامكان الوصول اليه بالخروج من الدالة التي تم تعريفه فيها.
كود :
def my_var(i):
   try:
       print("before ...")
       print("y = {}".format(y))
   except NameError:
       print("'y' is not yet defined.")
   y = i
   print("After...")
   print("y = {}".format(y))

my_var(20)
print(y)                        # Exception: NameError
هذا المثال يبين أن بيثون يقرأ السكربت تعليمة بعد الاخرى: هو في اول الدالة لا يعلم بوجود متغير باسم y رغم أننا مررنا له قيمة كوسيط، لذلك يطلق استثناء. بعد الخروج من الدالة حاولنا طباعة قيمة y لكن بيثون لا يجد المتغير، لأنه معرف في نطاق الدالة وبخروجنا منها تم استرجاع ذلك النطاق من الذاكرة ولم يعد له وجود (لم يعد بالامكان الوصول اليه).
## تعميم
تكون المتغيرات معزولة تماما داخل كتلة تعليمات أو داخل وحدة عبر ما يسمى 'مجال التسمية' (namespace). في بيثون مجال التسمية يجمع عددا من المتغيرات تنتمي الى كائن ما: الوحدة والدالة والفئة ومثيل الفئة كل منها تقوم بتعريف مجال تسمية خاص بها. هذا المفهوم موجود في لغات أخرى لكن بطريقة مختلفة وعادة تتطلب مجهودا اضافيا من المبرمج لعزل المتغيرات داخل مجالات تسمية. في بيثون مجرد انشائنا لوحدة جديدة يوفر مجال تسمية خاص بها وبالتالي تكون المتغيرات معزولة بمجرد كتابتنا لأول سطر كود. لنر كيف تقوم الوحدات بعزل المتغيرات عبر مجالات التسمية. سنقوم بانشاء وحدة باسم spam.py ونعرف داخلها متغيرا ودالة:
كود :
x = 1                   # 2
def f():                # 2 - 3
   print(x)            # 2
ووحدة ثانية باسم eggs.py نستورد داخلها الوحدة spam ونعرف متغيرا ودالة كما يلي:
كود :
import spam             # 2
x = 2                   # 4
def f():                # 5 - 3
   print(x)            # 4
f()                     # 5
spam.f()                # 6
print(spam.x)           # 7
بعد حفظ الوحدتين ننتقل الى المجلد ونفتح طرفية ونكتب:
كود :
python3 eggs.py         # 1
سنحلل ما حدث في ذاكرة الحاسب: خذ قلما وورقة وارسم مخططا للنقاط التالية حتى يتيسر عليك فهمها.
قام النظام بتخصيص مساحة من الذاكرة للكائنات ومساحة اخرى لمجالات التسمية. ما يهمنا هو المساحة المخصصة لمجالات التسمية:
# 1- داخل مساحة الذاكرة المخصصة لمجالات التسمية تم تخصيص مجال تسمية للوحدة eggs
# 2- عند قراءة سطر import spam خصص مجال تسمية خاص بالوحدة spam وضع فيه تعريف x و f (لكن دون تخصيص مجال تسمية للدالة f)
# 3- بالنسبة للدوال سيتم انشاء مجال تسمية خاص بكل منها عند استدعائها ثم يتم استرجاعه عند الخروج من الدالة.
# 4- عند قراءة السطر x = 2 قام النظام بعريف المتغير x داخل المجال المخصص لـeggs وربطه بالقيمة 2 في مساحة الذاكرة المخصصة للكائنات
# 5- عند استدعاء الدالة f قام النظام بتخصيص مجال تسمية لها. داخل الدالة بحث النظام عن x في المجال المحلي للدالة لكنه لم يجده، فبحث في المجال المحلي للوحدة eggs فوجده وطبع لنا القيمة، ثم، عند الخروج من الدالة، استرجع النظام مجال التسمية الذي كان قد خصصه للدالة.
# 6- عند السطر spam.f قام النظام بتخصيص مجال تسمية للدالة داخل المجال المخصص لـspam واتبع نفس المراحل، حيث بحث عن x في مجال التسمية الخاص بـf ولما لم يجده بحث عنه في المجال الأشمل اي المجال المخصص للوحدة spam وهناك وجده فطبع القيمة (1)، وعند الخروج من الدالة استرجع مساحة الذاكرة التي خصصها لها.
# 7- أخيرا، عند سطر طباعة spam.x بحث النظام عن x في المجال المخصص لـspam
اذا اردنا ان نلخص كل ما حدث ونعممه يمكننا ان نقول ان بيثون يبدأ البحث دائما في أقرب نطاق محلي للتعليمة ثم يتوسع تدريجيا في البحث، لذلك لا يشكل تسمية كائنات بنفس الاسم في مجالات تسمية مختلفة مشكلة بالنسبة للنظام (لكن قد يسبب مشاكل وصعوبات بالنسبة للمبرمج).
من المهم أيضا أن نتذكر أننا لا نستطيع تعديل قيمة متغير (التعيين مباشرة بواسطة =) من خارج النطاق الذي تم تعريف المتغير فيه. أما بالنسبة للكائنات التي لها وظائف تسمح بتعديلها، فذلك ممكن عبر تلك الوظائف: ذلك أننا عندما نمرر كائنا كوسيط لدالة فنحن انما نمرر مرجع للكائن نفسه وليس لقيمته. بالنسبة لمن لديهم بعض المعرفة بلغات برمجة اخرى كالسي++ او الجافا، تلك اللغات تمرر افتراضيا قيمة المتغير وليس المرجع او المؤشر.
كود :
t = []                  # قلنا أن الدالة تستطيع أن 'تقرأ' متغيرا معرفا خارجها
def my_var():           # لكن بالنسبة للكائنات القابلة للتعديل كالقوائم مثلا
   t.extend([5, 6, 7]) # يمكننا تعديل قائمة عبر وظائفها

print(t)

## المتغيرات العمومية (global variables)
وفر بيثون طريقة لتعديل متغير داخل دالة إذا كان معرفا خارج نطاق الدالة. هذه الطريقة تسمى المتغيرات العمومية
كود :
def global_var():
   global i
   i += 100

i = 50
global_var()
print(i)
ينصح بشدة بتجنب استخدام الكلمة المفتاحية global نظرا لما قد تسببه من تأثيرات جانبية. في بيثون3 يوجد كلمة مفتاحية أخرى تعدل متغيرا معرفا في الدوال المتداخلة nonlocal.
كود :
i = 50
def outsidef():
   i = 20
   def insidef():
       nonlocal i
       i += 100
       print("inside i = ", i)
   insidef()
   print("outside i =", i)


outsidef()
print("global i =", i)
## خاتمة
قد يبدو مفهوم مجالات التسمية معقدا في البداية، وأعترف أن شرحه نظريا أصعب من تجربته عمليا، لذلك أدعو من وجد صعوبات في فهم هذا الموضوع أن يجرب أمثلة أخرى عبر البحث عن python namespace في الانترنت مثلا.
الرد


التنقل السريع :


مستخدمين يتصفحوا هذا الموضوع: 1 ضيف