create - python for loop




الاختيار من قبل Python 3.5 لاختيار المفاتيح عند مقارنتها في القاموس (4)

عند إنشاء قاموس على النحو التالي:

dict = { True: 'yes', 1: 'No'}

عندما أقوم بتشغيله في مترجم Python التفاعلي ، يتم تمثيل dict بهذه الطريقة:

dict = {True: 'No'}

أتفهم أن القيمتين True و 1 متساوية بسبب إكراه الكتابة لأنه عند مقارنة الأنواع الرقمية ، يتم توسيع النوع الضيق إلى النوع الآخر (المنطقي هو عدد صحيح). هكذا فهمت من الوثائق ، عندما ندخل True == 1 Python بتحويل True إلى 1 ومقارنتها.

ما لا أفهمه هو سبب اختيار True كمفتاح بدلاً من 1 .

أنا في عداد المفقودين شيء؟


إذا كان المفتاح موجودًا بالفعل في القاموس ، فلن يتجاوز المفتاح القيمة المرتبطة فقط.

أعتقد أن الكتابة x = {True:"a", 1:"b"} تتماشى مع:

x = {}
x[True] = "a"
x[1] = "b"

وفي الوقت الذي يصل فيه إلى x[1] = "b" يكون المفتاح True موجودًا بالفعل في الإملاء ، فلماذا يغيره؟ لماذا لا تتجاوز القيمة المرتبطة فقط.


إنه بيان غامض.

المنطق: d = { True: 'no', 1: 'yes'}

عندما يقوم python بتقييم التعبير ، فإنه يقوم بذلك بالتتابع ، لذلك يكون مكافئًا لذلك.

d = dict() d[True] = 'no' d[1] = 'yes'

الثابت الثابت هو المفتاح ، لكن يتم تقييمه إلى 1 ، لذلك أنت فقط تحدد قيمة المفتاح مرتين.


يبدو أن الطلب هو السبب. مثال على الكود:

>>> d = {True: 'true', 1: 'one'}
>>> d
{True: 'one'}
>>> d = {1: 'one', True: 'true'}
>>> d
{1: 'true'}

يتم تطبيق القواميس كجداول تجزئة وهناك مفهومان مهمان عند إضافة مفاتيح / قيم هنا: التجزئة والمساواة .

لإدراج مفتاح / قيمة معينة ، يحسب Python أولاً قيمة تجزئة المفتاح. يتم استخدام قيمة التجزئة لتحديد صف الجدول الذي يجب أن يحاول Python أولاً وضع المفتاح / القيمة فيه.

إذا كان صف جدول التجزئة فارغًا ، رائع: يمكن إدخال المفتاح / القيمة الجديدة في القاموس ، مع ملء الصف الفارغ.

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

(إذا كانت المفاتيح غير متساوية ، يبحث Python في صفوف أخرى في الجدول حتى يجد المفتاح أو يصل إلى صف فارغ ، لكن هذا غير مناسب لهذا السؤال.)

عندما تكتب {True: 'yes', 1: 'No'} ، فأنت تخبر بيثون لإنشاء قاموس جديد ثم ملؤه بزوجين مفتاحين / قيمة. تتم معالجة هذه من اليسار إلى اليمين: True: 'yes' ثم 1: 'No' .

لدينا hash(True) يساوي 1. المفتاح True يسري في الصف 1 في جدول التجزئة والسلسلة 'yes' هي قيمتها.

بالنسبة للزوج التالي ، ترى Python أن hash(1) هي 1 أيضًا ، وهكذا تبدو في الصف 1 من الجدول. هناك شيء موجود بالفعل ، لذا تقوم Python الآن بفحص مفاتيح المساواة. لدينا 1 == True لذلك 1 يُعتبر المفتاح نفسه لـ True وهكذا يتم تغيير قيمته المقابلة إلى السلسلة 'No' .

ينتج عن هذا قاموس ذو إدخال واحد: {True: 'No'} .

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

  • يتم تحليل رمز Python {True: 'yes', 1: 'No'} في الرموز المميزة ويتم إعطاؤه للمترجم. بالنظر إلى بناء الجملة ، يعرف Python أنه يجب إنشاء قاموس باستخدام القيم الموجودة داخل الأقواس. رمز البايت لتحميل القيم الأربعة إلى مكدس الجهاز الظاهري ( LOAD_CONST ) ثم إنشاء القاموس ( BUILD_MAP ) في قائمة الانتظار.

  • يتم دفع القيم الثابتة الأربعة إلى أعلى المكدس بالترتيب الذي تظهر به:

    'No'
    1
    'yes'
    True
  • ثم يتم استدعاء شفرة التشغيل BUILD_MAP 2 (قام Python بحساب اثنين من أزواج المفتاح / القيمة). شفرة التشغيل هذه مسؤولة عن إنشاء القاموس فعليًا من العناصر الموجودة في الحزمة. يبدو مثل this :

    TARGET(BUILD_MAP) {
        int i;
        PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg);
        if (map == NULL)
            goto error;
        for (i = oparg; i > 0; i--) {
            int err;
            PyObject *key = PEEK(2*i);
            PyObject *value = PEEK(2*i - 1);
            err = PyDict_SetItem(map, key, value);
            if (err != 0) {
                Py_DECREF(map);
                goto error;
            }
        }
    
        while (oparg--) {
            Py_DECREF(POP());
            Py_DECREF(POP());
        }
        PUSH(map);
        DISPATCH();
    }

الخطوات الثلاث الرئيسية هنا هي كما يلي:

  1. يتم إنشاء علامة تجزئة فارغة باستخدام _PyDict_NewPresized . تحتاج القواميس الصغيرة (التي تحتوي على عدد قليل من العناصر ، مثل 2 في هذه الحالة) إلى جدول به ثمانية صفوف.

  2. يتم إدخال حلقة for ، بدءًا من 2 (في هذه الحالة) والعد التنازلي إلى 0. PEEK(n) هو ماكرو يشير إلى العنصر nth أسفل الحزمة. لذلك في التكرار الأول للحلقة ، سيكون لدينا

PyObject *key = PEEK(2*2);       /* item 4 down the stack */  
PyObject *value = PEEK(2*2 - 1); /* item 3 down the stack */

هذا يعني أن *key سيكون True وأن *value ستكون 'yes' في الحلقة الأولى. في الثانية سيكون 1 و 'No' .

  1. يتم استدعاء PyDict_SetItem في كل حلقة لوضع القيمة الحالية *key و *value في القاموس. هذه هي نفس الوظيفة التي تسمى عند كتابة dictionary[key] = value . يقوم بحساب تجزئة المفتاح لمعرفة مكان البحث أولاً في جدول التجزئة ، ثم ، إذا لزم الأمر ، قارن المفتاح بأي مفتاح موجود في هذا الصف (كما تمت مناقشته أعلاه).




dictionary