python - تعيين الحرفي يعطي نتيجة مختلفة من استدعاء وظيفة مجموعة




hash set (2)

الأمر كله مرتبط بالترتيب الذي تم به إنشاء المجموعة ، مقترنة بالأخطاء التي اكتشفتها مع سؤالك الآخر . يبدو أن الحرفي مبني بترتيب معاكس للتحويل من قائمة.

>>> {0, x, y}
set([0j, Decimal('0')])
>>> {y, x, 0}
set([0])

لماذا تقوم دالة الضبط باستئصال الخداع ، لكن تحليل مجموعة حرفية لا؟

>>> x = Decimal('0')
>>> y = complex(0,0)
>>> set([0, x, y])
{0}
>>> {0, x, y}
{Decimal('0'), 0j}

(بيثون 2.7.12. ربما نفس السبب الجذري this السؤال مماثل)


قم بتعيين اختبار للمساواة ، وإلى أن يتم إصدار إصدارات Python جديدة ، يمكن أن يختلف الترتيب الذي يقومون به بناءً على النموذج الذي تقوم بتسليم القيم للمجموعة قيد الإنشاء ، كما سأعرض أدناه.

نظرًا لأن 0 == x صحيح و 0 == y صحيح ، لكن x == y غير صحيح ، فالسلوك هنا غير محدد حقًا ، حيث تفترض المجموعة أن x == y يجب أن تكون صحيحة إذا كان أول اختبارين صحيحين أيضًا .

إذا قمت بعكس القائمة التي تم تمريرها إلى set() ، فستحصل على نفس الإخراج الذي تستخدمه حرفيًا ، لأن ترتيب اختبارات المساواة يتغير:

>>> set([y, x, 0])
set([0j, Decimal('0')])

ونفس الشيء لعكس الحرفي:

>>> {y, x, 0}
set([0])

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

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

>>> {y, 0, x}
set([Decimal('0'), 0j])
>>> {x, 0, y}
set([0j, Decimal('0')])

أن مجموعة الحرفي إضافة عناصر في الاتجاه المعاكس هو علة موجودة في جميع إصدارات بيثون التي تدعم بناء الجملة ، على طول الطريق حتى بيثون 2.7.12 و 3.5.2. تم إصلاحه مؤخرًا ، راجع العدد 26020 (جزء من 2.7.13 و 3.5.3 و 3.6 ، لم يتم إصدار أي منها حتى الآن). إذا نظرت إلى 2.7.12 ، يمكنك أن ترى أن BUILD_SET في ceval.c يقرأ المكدس من الأعلى إلى الأسفل:

# oparg is the number of elements to take from the stack to add
for (; --oparg >= 0;) {
    w = POP();
    if (err == 0)
        err = PySet_Add(x, w);
    Py_DECREF(w);
}

بينما يضيف الكود الثنائي عناصر إلى المكدس بترتيب عكسي (الضغط على الكومة أولاً):

>>> from dis import dis
>>> dis(compile('{0, x, y}', '', 'eval'))
  2           0 LOAD_CONST               1 (0)
              3 LOAD_GLOBAL              0 (x)
              6 LOAD_GLOBAL              1 (y)
              9 BUILD_SET                3
             12 RETURN_VALUE

الإصلاح هو قراءة العناصر من المكدس في ترتيب عكسي؛ يستخدم الإصدار Python 2.7.13 PEEK() بدلاً من POP()STACKADJ() لإزالة العناصر من المكدس فيما بعد):

for (i = oparg; i > 0; i--) {
    w = PEEK(i);
    if (err == 0)
        err = PySet_Add(x, w);
    Py_DECREF(w);
}
STACKADJ(-oparg);

قضية اختبار المساواة لها نفس السبب الجذري للسؤال الآخر ؛ تواجه الفئة Decimal() بعض مشكلات المساواة مع complex هنا ، والتي تم إصلاحها في بيثون 3.2 (عن طريق إجراء مقارنات تدعم Decimal() مع complex وعدد قليل من الأنواع الرقمية الأخرى التي لم تدعمها من قبل ).





python-internals