[python] بناء بيثون إيتراتور الأساسية


Answers

هناك أربع طرق لبناء وظيفة متكررة:

أمثلة:

# generator
def uc_gen(text):
    for char in text:
        yield char.upper()

# generator expression
def uc_genexp(text):
    return (char.upper() for char in text)

# iterator protocol
class uc_iter():
    def __init__(self, text):
        self.text = text
        self.index = 0
    def __iter__(self):
        return self
    def __next__(self):
        try:
            result = self.text[self.index].upper()
        except IndexError:
            raise StopIteration
        self.index += 1
        return result

# getitem method
class uc_getitem():
    def __init__(self, text):
        self.text = text
    def __getitem__(self, index):
        result = self.text[index].upper()
        return result

لرؤية جميع الطرق الأربعة في العمل:

for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
    for ch in iterator('abcde'):
        print ch,
    print

مما يؤدي إلى:

A B C D E
A B C D E
A B C D E
A B C D E

ملاحظة :

لا يمكن reversed() نوعي uc_gen ( uc_gen و uc_genexp ) reversed() ؛ uc_iter البسيط ( uc_iter ) إلى الأسلوب السحري __reversed__ (الذي يجب أن يعيد __reversed__ جديدًا إلى الخلف) ؛ و getitem iteratable ( uc_getitem ) يجب أن يكون لديك طريقة سحرية __len__ :

    # for uc_iter
    def __reversed__(self):
        return reversed(self.text)

    # for uc_getitem
    def __len__(self)
        return len(self.text)

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

# generator
def even_gen():
    result = 0
    while True:
        yield result
        result += 2


# generator expression
def even_genexp():
    return (num for num in even_gen())  # or even_iter or even_getitem
                                        # not much value under these circumstances

# iterator protocol
class even_iter():
    def __init__(self):
        self.value = 0
    def __iter__(self):
        return self
    def __next__(self):
        next_value = self.value
        self.value += 2
        return next_value

# getitem method
class even_getitem():
    def __getitem__(self, index):
        return index * 2

import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
    limit = random.randint(15, 30)
    count = 0
    for even in iterator():
        print even,
        count += 1
        if count >= limit:
            break
    print

ما هي النتائج (على الأقل لعينة التشغيل):

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
Question

كيف يمكن إنشاء وظيفة تكرارية (أو كائن مكرر) في python؟




أرى بعضكم يفعلون return self في __iter__ . أردت فقط ملاحظة أن __iter__ نفسها يمكن أن تكون مولدًا (وبالتالي إزالة الحاجة لـ __next__ StopIteration استثناءات StopIteration )

class range:
  def __init__(self,a,b):
    self.a = a
    self.b = b
  def __iter__(self):
    i = self.a
    while i < self.b:
      yield i
      i+=1

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




هذه وظيفة قابلة للتكرار بدون yield . إنها تستفيد من وظيفة iter والإغلاق الذي يحافظ على الحالة في list (mutlable) قابلة للتغيير في النطاق المرفق لـ python 2.

def count(low, high):
    counter = [0]
    def tmp():
        val = low + counter[0]
        if val < high:
            counter[0] += 1
            return val
        return None
    return iter(tmp, None)

بالنسبة إلى بايثون 3 ، يتم الإبقاء على حالة الإغلاق غير قابلة للتغيير في النطاق nonlocal ويتم استخدام غير nonlocal في النطاق المحلي لتحديث متغير الحالة.

def count(low, high):
    counter = 0
    def tmp():
        nonlocal counter
        val = low + counter
        if val < high:
            counter += 1
            return val
        return None
    return iter(tmp, None)  

اختبار؛

for i in count(1,10):
    print(i)
1
2
3
4
5
6
7
8
9





Related