كائنات ChainMap‎ في بايثون

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث

يقدّم الصنف Chainmap طريقة سريعة لربط عدد من عمليات الربط mappings ليصبح بالإمكان التعامل معها كوحدة واحدة. وعادة ما تكون هذه الطريقة أسرع من إنشاء قاموس جديد واستدعاء التابع update()‎ مرّات عدة.

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

البنية العامة

class collections.ChainMap(*maps)

يجمع الصنف CmainMap عددًا من القواميس أو وسائل الربط الأخرى لإنشاء عرض مفرد قابل للتحديث.

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

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

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

تُدرَج كائنات الربط الضمنية في صنف ChainMap بالإشارة (by reference)، لذا عند تحديث أي كائن من كائنات الربط فإنّ التحديثات تنعكس على الصنف ChainMap.

يدعم الصنف ChainMap جميع التوابع الخاصة بالقواميس، إلى جانب الوسيط maps والتابع  new_child()‎ لإنشاء سياقات فرعية subcontexts جديدة والخاصية parents التي تتيح الوصول إلى جميع كائنات الربط باستثناء الكائن الأول:

الوسيط maps

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

التابع new_child

يعيد التابع صنف ChainMap جديد يتضمّن كائن ربط جديد متبوعًا بجميع كائنات الربط الموجودة في النسخة الحالية.

الخاصية parents

خاصّية تعيد صنف ChainMap جديد يتضمّن جميع كائنات الربط في النسخة الحالية باستثناء الكائن الأول. تفيد هذا الخاصية في تجاوز كائن الربط الأول في عملية البحث. تستخدم هذه الخاصية في حالات مشابهة لتلك التي تستدعي استخدام الكلمة المفتاحية nonlocal في النطاقات المتشعّبة، إلى جانب الحالات التي تستدعي استخدام التابع الداخلي super()‎. جدير بالذكر أنّ الإشارة إلى d.parents تكون مكافئة للتعبير ChainMap(*d.maps[1:])‎.

أمثلة على الصنف CnainMap

يعرض هذا القسم طرقًا متعددة للعمل مع كائنات الربط المتسلسلة chained maps.

يحاكي المثال التالي سلسلة البحث الداخلية في بايثون:

import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))

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

import os, argparse
defaults = {'color': 'red', 'user': 'guest'}
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k:v for k, v in vars(namespace).items() if v}
combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])

بعض الأمثلة على طرق استخدام الصنف ChainMap لمحاكاة السياقات المشتعّبة:

c = ChainMap()        # إنشاء سياق جذري
d = c.new_child()     # إنشاء سياق ابن متشعب
e = c.new_child()     # سياق ابن متشعب من السياق الأب c ولكنه غير مرتبط بالسياق الابن d
e.maps[0]             # locals()‎ قاموس السياق الحالي -- يشبه الدالة الداخلية
e.maps[-1]            # globals() سياق الجذر -- يشبه الدالة الداخلية 
e.parents             # nonlocals سلسلة النطاق الشامل -- يشبه
d['x']                # الحصول على المفتاح الأول في سلسلة السياقات
d['x'] = 1            # تعيين قيمة في السياق الحالي
del d['x']            # الحذف من السياق الحالي
list(d)               # جميع القيم المتشعبة
k in d                # التحقق من جميع القيم المتشعبة
len(d)                # عدد القيم المتشعبة
d.items()             # جميع العناصر المتشعبة
dict(d)               # التحويل إلى قاموس عادي

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

class DeepChainMap(ChainMap):
    'Variant of ChainMap that allows direct updates to inner scopes'
    def __setitem__(self, key, value):
        for mapping in self.maps:
            if key in mapping:
                mapping[key] = value
                return
class DeepChainMap(ChainMap):
    'Variant of ChainMap that allows direct updates to inner scopes'

    def __setitem__(self, key, value):
        for mapping in self.maps:
            if key in mapping:
                mapping[key] = value
                return
        self.maps[0][key] = value

    def __delitem__(self, key):
        for mapping in self.maps:
            if key in mapping:
                del mapping[key]
                return
        raise KeyError(key)

>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange'         # تحديث مفتاح موجود في مستويين إلى الأسفل
>>> d['snake'] = 'red'           # تضاف المفاتيح الجديدة إلى أعلى قاموس ضمن السلسلة
>>> del d['elephant']            # حذف مفتاح موجود في مستوى واحد إلى الأسفل
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

انظر أيضًا

  • كائنات namedtuple: :دالة مولِّدة factory function لإنشاء أصناف فرعية من tuple تتضمن حقولًا مسمّاة
  • كائنات deque: :حاوية شبيهة بالقوائم تمتاز بأدائها السريع في إضافة العناصر وحذفها في كلا الطرفين.
  • كائنات Counter: :صنف فرعي من الصنف dict الهدف منه عدّ الكائنات القابلة للتقطيع hashable
  • كائنات OrderedDict: :صنف فرعي من الصنف dict يمكنه تذكّر ترتيب العناصر عند إضافتها
  • كائنات defaultdict: :صنف فرعي من الصنف dict يستدعي دالة مولّدة تقدّم القيم المفقودة
  • كائنات UserDict: :تغليف حول كائنات القواميس لتسهيل عملية تفريع أصناف القواميس
  • كائنات UserList: :تغليف حول كائنات القوائم لتسهيل عملية تفريع أصناف القوائم
  • كائنات UserString: :تغليف حول كائنات السلاسل النصية لتسهيل عملية تفريع أصناف السلاسل النصية

مصادر