Temel Python yineleyici kurmak

oy
442

İnsan nasıl python iteratif fonksiyonunu (veya yineleyici nesne) yaratacak?

Oluştur 20/08/2008 saat 23:36
kaynak kullanıcı
Diğer dillerde...                            


9 cevaplar

oy
97

Her şeyden önce itertools modülünde bir yineleyici faydalı olacaktır hangi durumlarda her türlü için son derece yararlıdır, ancak burada python bir yineleyici oluşturmak için ihtiyaç vardır:

Yol ver

Bu harika değil mi? Verim normal yerine kullanılabilir dönüş fonksiyonu olarak. Sadece aynı nesnesi döndüren, ancak bunun yerine devleti tahrip ve çıkarken nedeniyle, bir sonraki iterasyon yürütmek istediğinizde durumunu kaydeder. İşte doğrudan çekti eylem bunun bir örneğidir itertools fonksiyon listesinde :

 def count(n=0):
     while True:
         yield n
         n += 1

Fonksiyonları açıklaması (öyle belirtildiği gibi sayımı () ... itertools modülünden fonksiyonu), bu n ile başlayan ardışık tamsayılar döndüren bir yineleyici üretir.

Jeneratör ifadeler solucanlar bambaşka kutu vardır (müthiş solucanlar!). Onlar yerine kullanılabilecek Liste Anlama liste comprehensions bir değişkene atanmamış ise kullanımdan sonra imha edilir bellekte bir liste oluşturmak, ancak jeneratör ifadeleri süslü bir yoldur bir Jeneratör Object ... yaratabilir (bellekten tasarruf etmek ) yineleyici söyleyerek. Burada bir jeneratör sentezleme tanımının bir örneği aşağıda verilmektedir:

gen = (n for n in xrange(0,11))

Bu dizi, 0 ile 10 arasında olduğu, önceden belirlenmiş olması dışında yukarıdaki yineleyici tanımına çok benzerdir.

Sadece bulundu () xrange (... Bunu daha önce de görmemişti şaşırdı) ve yukarıdaki örnekte bunu ekledi. xrange () bir iterable versiyonu olan aralıkta () listesini prebuilding avantajına sahiptir. Eğer tekrarlatacak verinin dev külliyatını vardı ve sadece bunu yapmak için çok fazla bellek olsaydı çok yararlı olacaktır.

Cevap 20/08/2008 saat 23:36
kaynak kullanıcı

oy
517

Python yineleyici nesneleri temelde onlar iki yöntem sağlamak anlamına yineleyici protokolü, uygun: __iter__() ve next(). __iter__Döner yineleyici nesne ve dolaylı döngüler başında denir. next()Yöntem aşağıdaki değerini verir ve dolaylı her döngü artan çağrılır. next()örtülü iterating durdurmak için yapıları döngü tarafından yakalanır dönmek için artık değeri vardır bir StopIteration durum oluşturur.

İşte bir sayaç basit bir örnek:

class Counter:
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def next(self): # Python 3: def __next__(self)
        if self.current > self.high:
            raise StopIteration
        else:
            self.current += 1
            return self.current - 1


for c in Counter(3, 8):
    print c

Bu yazdırır:

3
4
5
6
7
8

Bu önceki yanıtta örtülü olarak, bir jeneratör kullanarak yazmak daha kolaydır:

def counter(low, high):
    current = low
    while current <= high:
        yield current
        current += 1

for c in counter(3, 8):
    print c

baskılı çıkış aynı olacaktır. Kaputun altında, jeneratör nesne yineleyici protokolünü destekleyen ve sınıf Sayaç kabaca benzer bir şey yapar.

David Mertz makalesi, Iterators ve Basit Jeneratörler , oldukça iyi bir giriştir.

Cevap 23/08/2008 saat 15:57
kaynak kullanıcı

oy
324

iteratif faaliyetleri oluşturmak için dört yolu vardır:

Örnekler:

# 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

eylem dört yöntemi görmek için:

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

Hangi sonuçlanır:

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

Not :

Iki jeneratör çeşitleri ( uc_genve uc_genexp) olamaz reversed(); Düz yineleyici ( uc_iter) gerekir __reversed__(geriye kalan yeni bir yineleyici dönmelidir) sihirli yöntem; ve GetItem iteratable ( uc_getitem) olması gerekir __len__sihirli yöntem:

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

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

Sonsuz lazily değerlendirilen yineleyici hakkında Albay Panik ikincil soruya cevap vermek için burada yukarıdaki dört yöntemden her kullanılmak suretiyle bu örnekler:

# 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

Hangi (en azından benim numune çalışması için) ile sonuçlanır:

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
Cevap 24/09/2011 saat 21:13
kaynak kullanıcı

oy
81

Bazılarınızın yaptığını görüyorum return selfiçinde __iter__. Sadece dikkat etmek istediğini __iter__kendisi (dolayısıyla ihtiyacını ortadan kaldırarak bir jeneratör olabilir __next__ve yetiştirme StopIterationistisnalar)

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

Tabii burada bir de doğrudan bir jeneratörü hale getirebileceğini, ancak daha karmaşık sınıflar için yararlı olabilir.

Cevap 27/07/2012 saat 14:05
kaynak kullanıcı

oy
3

Bu olmadan bir iterable fonksiyondur yield. Bu faydalanmak iterfonksiyonu ve (bir değişken içinde 's durumunu tutan bir kapatma listpiton 2 kapatan kapsamında).

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)

Python 3 için, kapatma devlet kapatan kapsamında değişmez bir tutulur ve nonlocaldevlet değişkeni güncellemek için yerel kapsamda kullanılır.

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)  

Ölçek;

for i in count(1,10):
    print(i)
1
2
3
4
5
6
7
8
9
Cevap 03/03/2016 saat 15:55
kaynak kullanıcı

oy
7

Bu soru değil yineleyiciler hakkında, iterable nesneler ile ilgili. Python'da sekanslar, çok çok bir şekilde tekrarlanabilir olduğundan bir iterable sınıfı vermek, yani bir dizi benzemesi için yapmak için __getitem__ve __len__yöntemler. Ben Python 2. ve 3. Bu test ettik.

class CustomRange:

    def __init__(self, low, high):
        self.low = low
        self.high = high

    def __getitem__(self, item):
        if item >= len(self):
            raise IndexError("CustomRange index out of range")
        return self.low + item

    def __len__(self):
        return self.high - self.low


cr = CustomRange(0, 10)
for i in cr:
    print(i)
Cevap 21/03/2016 saat 15:39
kaynak kullanıcı

oy
1

Eğer kısa ve basit bir şey arıyorsanız, belki sizin için yeterli olacaktır:

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

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

kullanım örneği:

In [3]: a = A([2,3,4])

In [4]: [i for i in a]
Out[4]: [2, 3, 4]
Cevap 26/04/2018 saat 07:38
kaynak kullanıcı

oy
0

Burada Matt Gregory'nin cevap esinlenerek olan a, b, ..., z, aa, ab, ..., zz, aaa, aab, ..., zzy, zzz dönecektir biraz daha karmaşık yineleyici

    class AlphaCounter:
    def __init__(self, low, high):
        self.current = low
        self.high = high

    def __iter__(self):
        return self

    def __next__(self): # Python 3: def __next__(self)
        alpha = ' abcdefghijklmnopqrstuvwxyz'
        n_current = sum([(alpha.find(self.current[x])* 26**(len(self.current)-x-1)) for x in range(len(self.current))])
        n_high = sum([(alpha.find(self.high[x])* 26**(len(self.high)-x-1)) for x in range(len(self.high))])
        if n_current > n_high:
            raise StopIteration
        else:
            increment = True
            ret = ''
            for x in self.current[::-1]:
                if 'z' == x:
                    if increment:
                        ret += 'a'
                    else:
                        ret += 'z'
                else:
                    if increment:
                        ret += alpha[alpha.find(x)+1]
                        increment = False
                    else:
                        ret += x
            if increment:
                ret += 'a'
            tmp = self.current
            self.current = ret[::-1]
            return tmp

for c in AlphaCounter('a', 'zzz'):
    print(c)
Cevap 13/07/2018 saat 16:34
kaynak kullanıcı

oy
0

Bu sayfadaki tüm cevaplar karmaşık bir nesne için gerçekten harika. Fakat nitelikleri olarak yerleşik yineleyici türlerini içeren olanlar için, gibi str, list, setveya dict, ya herhangi uygulanması collections.Iterable, kendi sınıfında bazı şeyleri atlayabilirsiniz.

class Test(object):
    def __init__(self, string):
        self.string = string

    def __iter__(self):
        # since your string is already iterable
        return (ch for ch in string)

Bu gibi kullanılabilir:

for x in Test("abcde"):
    print(x)

# prints
# a
# b
# c
# d
# e
Cevap 14/08/2018 saat 07:25
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more