python - صيغة فهم قائمة متداخلة متقدمة



syntax scope list-comprehension (5)

التوسيع على إجابة لي ريان قليلاً:

شيء = (x لـ x في النطاق (10) إذا كانت x٪ 2 == i لـ i في النطاق (2))

ما يعادل:

def _gen1():
    for x in range(10):
        if x%2 == i:
            for i in range(2):
                yield x
something = _gen1()

في حين أن الإصدار بين قوسين يساوي:

def _gen1():
    def _gen2():
        for x in range(10):
            if x%2 == i:
                yield x

    for i in range(2):
        yield _gen2()
something = _gen1()

هذا بالفعل يعطي المولدين:

[<generator object <genexpr> at 0x02A0A968>, <generator object <genexpr> at 0x02A0A990>]

لسوء الحظ ، فإن المولدات التي تنتجها غير مستقرة إلى حد ما حيث يعتمد الإنتاج على طريقة استهلاكك لها:

>>> gens = ((x for x in range(10) if x%2==i) for i in range(2))
>>> for g in gens:
        print(list(g))

[0, 2, 4, 6, 8]
[1, 3, 5, 7, 9]
>>> gens = ((x for x in range(10) if x%2==i) for i in range(2))
>>> for g in list(gens):
        print(list(g))

[1, 3, 5, 7, 9]
[1, 3, 5, 7, 9]

نصيحتي هي كتابة وظائف المولد بالكامل: أعتقد أن محاولة إجراء الفحص الصحيح على i دون القيام بذلك قد تكون مستحيلة.

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

كنت أحاول بشكل أساسي كتابة مولد ينتج مولدات كهربائية. سيبدو المولد البسيط الذي يستخدم فهم القائمة كالتالي:

(x for x in range(10) if x%2==0) # generates all even integers in range(10)

ما كنت أحاول القيام به هو أن أكتب مولدًا ينتج مولدين - أولهما توليد الأرقام الزوجية في النطاق (10) والثاني أنتج الأرقام الفردية في المدى (10). لهذا ، فعلت:

>>> (x for x in range(10) if x%2==i for i in range(2))
<generator object <genexpr> at 0x7f6b90948f00>

>>> for i in g.next(): print i
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
UnboundLocalError: local variable 'i' referenced before assignment
>>> g.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> g = (x for x in range(10) if x%2==i for i in range(2))
>>> g
<generator object <genexpr> at 0x7f6b90969730>
>>> g.next()
Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 1, in <genexpr>
    UnboundLocalError: local variable 'i' referenced before assignment

لا أفهم لماذا يتم الإشارة إلى "أنا" قبل التعيين

اعتقدت أنه ربما كان هناك علاقة مع i in range(2) ، لذلك فعلت:

>>> g = (x for x in range(10) if x%2==i for i in [0.1])
>>> g
<generator object <genexpr> at 0x7f6b90948f00>
>>> g.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
UnboundLocalError: local variable 'i' referenced before assignment

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

>>> [x for x in range(10) if x%2==i for i in range(2)]
[1, 1, 3, 3, 5, 5, 7, 7, 9, 9]

والتي توقعت أن تكون هي نفسها:

>>> l = []
>>> for i in range(2):
...     for x in range(10):
...             if x%2==i:
...                     l.append(x)
... 
>>> l
[0, 2, 4, 6, 8, 1, 3, 5, 7, 9] # so where is my list comprehension malformed?

ولكن عندما جربتها على حدس ، كان هذا:

>>> [[x for x in range(10) if x%2==i] for i in range(2)]
[[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]] # so nested lists in nested list comprehension somehow affect the scope of if statements? :S

لذلك اعتقدت أنه قد يكون مشكلة مع مستوى النطاق if يعمل في البيان. لذلك حاولت ذلك:

>>> [x for x in range(10) for i in range(2) if x%2==i]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

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

ملاحظة: في حين يثبت قراءة السؤال ، أدركت أن هذا يبدو قليلا مثل سؤال الواجب المنزلي - فهو ليس كذلك.


تحتاج إلى استخدام بعض الأقواس:

((x for x in range(10) if x%2==i) for i in range(2))

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

[>>> [x for x in range (10) if x٪ 2 == i for i in range (2)] [1، 1، 3، 3، 5، 5، 7، 7، 9، 9]

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

تصحيح:

المكافئ للحلقة من أجل:

(x for x in range(10) if x%2==i for i in range(2))

سيكون:

l = []
for x in range(10):
    if x%2 == i:
        for i in range(2):
            l.append(x)

والذي يعطي أيضا خطأ في الاسم.

EDIT2:

النسخة المعدلة:

((x for x in range(10) if x%2==i) for i in range(2))

ما يعادل:

li = []
for i in range(2):
    lx = []
    for x in range(10):
        if x%2==i:
            lx.append(x)
    li.append(lx)

يؤدي المكافئ الذي يقدمه Lie Ryan إلى الحلقة التالية ، والتي يبدو أنها تعمل بشكل جيد:

[x for i in range(2) for x in range(10) if i == x%2]

المخرجات

[0, 2, 4, 6, 8, 1, 3, 5, 7, 9]

الكذب لديه الجواب على السؤال النحوي. اقتراح: لا تدخل أشياء كثيرة في جسم المولد. وظيفة أكثر قابلية للقراءة.

def make_generator(modulus):
    return (x for x in range(10) if x % 2 == modulus)
g = (make_generator(i) for i in range(2))

سبب آخر لاستخدام الفهم قائمة أكثر من الخريطة () وفلتر () هو أن Psyco لا يمكن تجميع هذه الوظائف.

انظر http://psyco.sourceforge.net/





python syntax scope list-comprehension