سؤال

عند استخدام فهم القائمة أو in الكلمة الأساسية في سياق حلقة، أي:

for o in X:
    do_something_with(o)

أو

l=[o for o in X]
  • كيف آلية وراء in يعمل؟
  • ما هي الوظائف\الطرق الموجودة داخل X هل يتصل؟
  • لو X يمكن الالتزام بأكثر من طريقة، ما هي الأسبقية؟
  • كيفية كتابة فعالة X, ، بحيث يكون فهم القائمة سريعًا؟
هل كانت مفيدة؟

المحلول

أفيك، الإجابة الكاملة والصحيحة.

for, ، سواء في الحلقات أو قائمة الفهم أو المكالمات iter() على X. iter() سوف يعود للتكرار إذا X إما لديه __iter__ طريقة أو أ __getitem__ طريقة.فإذا نفذت الأمرين __iter__ يستخدم.إذا لم يكن لديك لا تحصل عليه TypeError: 'Nothing' object is not iterable.

ينفذ هذا أ __getitem__:

class GetItem(object):
    def __init__(self, data):
        self.data = data

    def __getitem__(self, x):
        return self.data[x]

الاستخدام:

>>> data = range(10)
>>> print [x*x for x in GetItem(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

وهذا مثال للتنفيذ __iter__:

class TheIterator(object):
    def __init__(self, data):
        self.data = data
        self.index = -1

    # Note: In  Python 3 this is called __next__
    def next(self):
        self.index += 1
        try:
            return self.data[self.index]
        except IndexError:
            raise StopIteration

    def __iter__(self):
        return self

class Iter(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return TheIterator(data)

الاستخدام:

>>> data = range(10)
>>> print [x*x for x in Iter(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

كما ترى، فأنت بحاجة إلى تنفيذ مكرِّر، و __iter__ الذي يعيد المكرر.

يمكنك الجمع بينهما:

class CombinedIter(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        self.index = -1
        return self

    def next(self):
        self.index += 1
        try:
            return self.data[self.index]
        except IndexError:
            raise StopIteration

الاستخدام:

>>> well, you get it, it's all the same...

ولكن بعد ذلك لا يمكن أن يكون لديك سوى مكرر واحد يعمل مرة واحدة.حسنًا، في هذه الحالة يمكنك القيام بذلك:

class CheatIter(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return iter(self.data)

لكن هذا يعد غشًا لأنك تقوم فقط بإعادة استخدام __iter__ طريقة list.الطريقة الأسهل هي استخدام العائد والتصنيع __iter__ في مولد:

class Generator(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        for x in self.data:
            yield x

هذه الأخيرة هي الطريقة التي أوصي بها.سهلة وفعالة.

نصائح أخرى

X يجب أن تكون قابلة للتكرار.يجب أن تنفذ __iter__() الذي يقوم بإرجاع كائن مكرر؛يجب تنفيذ كائن التكرار next(), ، والذي يقوم بإرجاع العنصر التالي في كل مرة يتم استدعاؤه أو رفعه StopIteration إذا لم يكن هناك العنصر التالي.

القوائم والصفوف والمولدات كلها قابلة للتكرار.

لاحظ أن سهل for يستخدم المشغل نفس الآلية.

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

   TARGET(FOR_ITER)
        /* before: [iter]; after: [iter, iter()] *or* [] */
        v = TOP();

        /*
          Here tp_iternext corresponds to next() in Python
        */
        x = (*v->ob_type->tp_iternext)(v); 
        if (x != NULL) {
            PUSH(x);
            PREDICT(STORE_FAST);
            PREDICT(UNPACK_SEQUENCE);
            DISPATCH();
        }
        if (PyErr_Occurred()) {
            if (!PyErr_ExceptionMatches(
                            PyExc_StopIteration))
                break;
            PyErr_Clear();
        }
        /* iterator ended normally */
        x = v = POP();
        Py_DECREF(v);
        JUMPBY(oparg);
        DISPATCH();

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

X يجب أن يكون كائنًا قابلاً للتكرار، مما يعني أنه يجب أن يكون له __iter__() طريقة.

لذلك، لبدء أ for..in حلقة، أو فهم القائمة، أولا X__iter__() يتم استدعاء الطريقة للحصول على كائن مكرر؛ثم هذا الكائن next() يتم استدعاء الطريقة لكل تكرار حتى StopIteration مرفوع، وعند هذه النقطة يتوقف التكرار.

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

ربما يساعد هذا (البرنامج التعليمي http://docs.python.org/tutorial/classes.html القسم 9.9):

وراء الكواليس ، يستدعي البيان ITER () على كائن الحاوية.تقوم الدالة بإرجاع كائن Iterator الذي يحدد الطريقة التالية () التي تصل إلى العناصر في الحاوية واحدة في وقت واحد.عندما لا يكون هناك المزيد من العناصر ، فإن NEXT () يثير استثناء التوقف الذي يخبر الحلقة لإنهاء.

للإجابة على أسئلتكم:

كيف تعمل الآلية الموجودة خلفنا؟

إنها نفس الآلية المستخدمة في حلقات for العادية، كما لاحظ آخرون بالفعل.

ما هي الوظائف/الطرق داخل X التي تستدعيها؟

كما هو مذكور في التعليق أدناه، فإنه يدعو iter(X) للحصول على مكرر.لو X لديه وظيفة الأسلوب __iter__() تم تعريفه، سيتم استدعاء هذا لإرجاع مكرر؛وإلا إذا X يحدد __getitem__(), ، سيتم استدعاء هذا بشكل متكرر للتكرار X.راجع وثائق بايثون لـ iter() هنا: http://docs.python.org/library/functions.html#iter

إذا كان X يمكنه الالتزام بأكثر من طريقة، فما هي الأسبقية؟

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

ترتيب دقة الطريقة (MRO) في فئات بايثون ذات النمط الجديد

كيف تكتب علامة X فعالة بحيث يكون فهم القائمة سريعًا؟

أقترح عليك قراءة المزيد عن التكرارات والمولدات في بايثون.إحدى الطرق السهلة لإجراء أي تكرار لدعم الفصل الدراسي هي إنشاء وظيفة مولد لـ iter().هنا مناقشة للمولدات:

http://linuxgazette.net/100/pramode.html

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top