2016-04-11 39 views
0

Aşağıdaki iki seçenek arasından, yinelenen ve daha fazla mantık eklemek için daha çekici (okunabilir kod, daha pythonic, verimlilik vb.) Nedir ve gelecekte daha fazla mantık eklemek istiyorum Her dönüş değeri 1)?Dönüş jeneratörü Geri Dönme Yok

Seçeneklerden biri, jeneratörü döndürür, diğeri, tüm yinelemeler tamamlandığında bir sonraki öğeyi ve None değerini döndürür.

Tercih edilen bir yöntem var mı? Evet ise neden? Bazı yöntemlerde sınırlama var mı, başka bir şey yok.

class Option1(): 
    def __init__(self): 
     self.current = 0 

    def get_next_batch(self, my_list): 
     if self.current == len(my_list): 
      self.current = 0 
      return None 
     self.current += 1 
     return [my_list[self.current-1]] 


class Option2(): 
     def __init__(self): 
      self.current = 0 

     def get_next_batch(self, my_list): 
      while self.current < len(my_list): 
       yield [my_list[self.current]] 
       self.current += 1 
      self.current = 0 
      raise StopIteration() 

Kullanımı: Her iki durumda da

o1 = Option1() 
o2 = Option2() 
arr = [1,2,3,4,5] 

a = o1.get_next_batch(arr) 

while a is not None: 
    print a 
    a = o1.get_next_batch(arr) 

for item in o2.get_next_batch(arr): 
    print item 

Çıktı: Neredeyse kesinlikle ikinci ile gitmek istiyorum

[1] 
[2] 
[3] 
[4] 
[5] 

cevap

1

. Daha az satır, yanlış giden şeyler için daha az fırsat.

def get_next_batch(my_list): 
    for item in my_list: 
     yield [item] 

arr = [1,2,3,4,5] 
for item in get_next_batch(arr): 
    print item 

Yan noktaları:

Ancak, yineleyici dışında current kullanmıyorsanız gibi ben sadece aşağı bütün olayları optimize olacaktır görünce. Sınıflarınızı python 2.7'deki object'dan her zaman koruyun ve python'da bir jeneratörü durdurmak için StopIteration'u yükseltmeyin - hatalara yol açabilecek kullanım dışı davranışlar. Bunun yerine return kullanın. Örneğin.

def get_next_batch(my_list): 
    for item in my_list: 
     if item > 3: 
      return 
     yield [item] 

batched = list(get_next_batch([1,2,3,4,5])) 
expected = [[1], [2], [3]] 
print batched == expected 

Bunun kolay döngüler için kullanmak yapmak için yukarı Option1 çeki düzen olabilir. Bunu yapmak için yineleyici protokolü ile yapabilirsiniz. Bu, sonraki öğeyi almak için self ve next yöntemini döndüren __iter__ yöntemidir. Örneğin.

class UsingNext(object): 

    def __init__(self, mylist): 
     self.current = 0 
     self.mylist = mylist 

    def __iter__(self): 
     return self 

    def next(self): # __next__ in python 3 
     if self.current >= len(self.mylist): 
      raise StopIteration 
     if self.current == 2: 
      self.current += 1 
      return "special" 
     item = self.mylist[self.current] 
     self.current += 1 
     return [item] 

class UsingYield(object): 

    def __init__(self, mylist): 
     self.mylist = mylist 

    def __iter__(self): 
     for current, item in enumerate(self.mylist): 
      if current == 2: 
       yield "special" 
       continue 
      yield [item] 

arr = range(1, 6) 
# both print 
# [1] 
# [2] 
# special 
# [4] 
# [5] 
for item in UsingNext(arr): 
    print item 
for item in UsingYield(arr): 
    print item 

Aklımda, jeneratör versiyonu daha temiz ve daha kolay anlaşılır.

+0

Jeneratör hakkında açıklamalar için teşekkürler. Akıma ihtiyacım var çünkü mantık daha karmaşık olduğunda farklı boyutlarda listeler getiriyorum. Bazı opsiyonların 'Option1' kullanılarak ve 'Option2' kullanılmadan gerçekleştirilebildiği bir senaryo var mı? Örneğin geri döndüğüm bir sonraki öğe, halihazırda iade ettiğim öğelere veya buna benzer bir şeye ne zaman bağlıdır? – Farseer

+1

Hayır, her ikisi de aynı şeyleri başarabilir. Jeneratörler kullanarak yineleyicileri modellemek sadece kavramsal olarak daha kolay (bence). – Dunes

+1

Option1'in bir for döngüsünde nasıl çalıştığı hakkında biraz bilgi eklendi. – Dunes

İlgili konular