генератор питона с проверкой на пустое состояние

Генераторы python – хорошая замена списков, в большинстве случаев ожидающих, где я хочу проверить пустое состояние, которое невозможно с помощью простых генераторов. Я пытаюсь написать оболочку, которая позволит проверять пустое состояние, но все еще ленив и дает преимущество генераторов.

class mygen: def __init__(self,iterable): self.iterable = (x for x in iterable) self.peeked = False self.peek = None def __iter__(self): if self.peeked: yield self.peek self.peeked = False for val in self.iterable: if self.peeked: yield self.peek self.peeked = False yield val if self.peeked: yield self.peek self.peeked = False def __nonzero__(self): if self.peeked: return True try: self.peek = self.iterable.next() self.peeked = True return True except: return False 
  1. Я думаю, что он ведет себя правильно, как простой генератор. Есть ли какой-нибудь угловой случай, который мне не хватает?
  2. Это не выглядит элегантно. Есть ли еще более питонический способ сделать то же самое?

Использование образца:

 def get_odd(l): return mygen(x for x in l if x%2) def print_odd(odd_nums): if odd_nums: print "odd numbers found",list(odd_nums) else: print "No odd numbers found" print_odd(get_odd([2,4,6,8])) print_odd(get_odd([2,4,6,8,7])) 

2 Solutions collect form web for “генератор питона с проверкой на пустое состояние”

Обычно я не использовал такой генератор. Существует идиоматический способ проверки, если итератор исчерпан:

 try: next_item = next(it) except StopIteration: # exhausted, handle this case 

Подстановка этой идиомы EAFP с помощью некоторой идиомы LBYL, специфичной для проекта, кажется запутанной и вообще не выгодной.

Тем не менее, вот как я мог бы реализовать это, если бы я действительно хотел:

 class MyIterator(object): def __init__(self, iterable): self._iterable = iter(iterable) self._exhausted = False self._cache_next_item() def _cache_next_item(self): try: self._next_item = next(self._iterable) except StopIteration: self._exhausted = True def __iter__(self): return self def next(self): if self._exhausted: raise StopIteration next_item = self._next_item self._cache_next_item() return next_item def __nonzero__(self): return not self._exhausted 

Используйте itertools.tee для реализации ненулевого теста и просто itertools.tee его при создании:

 from itertools import tee class NonZeroIterable(object): def __init__(self, iterable): self.__iterable, test = tee(iter(iterable)) try: test.next() self.__nonzero = True except StopIteration: self.__nonzero = False def __nonzero__(self): return self.__nonzero def __iter__(self): return self.__iterable 

Маленькая демонстрация:

 >>> nz = NonZeroIterable('foobar') >>> if nz: print list(nz) ... ['f', 'o', 'o', 'b', 'a', 'r'] >>> nz2 = NonZeroIterable([]) >>> if not nz2: print 'empty' ... empty 

Эта версия NonZeroIterable кэширует флаг; он, таким образом, только сообщает вам, был ли итератор не пустым в начале. Если вам нужно проверить итерабельность в других точках жизненного цикла, используйте версию Sven ; там флаг __nonzero__ будет сообщать вам после каждой итерации, если еще есть пункты, которые должны прийти.

Боковое примечание на вашем примере

Ваш примерный код слишком прост и не является хорошим аргументом для вашего использования; вы сначала проверяете на непустоту (который потенциально выполняет итерации по списку ввода для поиска нечетного числа), но затем исчерпает весь итератор. Следующий код был бы столь же эффективным и не требовал бы, чтобы вы изобретали способы сломать идиомы python:

 def print_odd(odd_nums): odd_nums = list(odd_nums) if odd_nums: print "odd numbers found", odd_nums else: print "No odd numbers found" 
  • Из python можно ли отслеживать назначения на уровне модуля до (другого) кода пользователя?
  • Эффективная охота на слова в скремблированных письмах
  • Ошибка возврата к фляге "Функция просмотра не возвращала ответ"
  • Расширение флеш-сессии и сеанс по умолчанию
  • Как вычислить точку пересечения двух строк в Python?
  • Загрузите файл на сервер флипсы python с помощью curl
  • Ошибка разблокировки типа при изменении моделей SqlAlchemy
  • прямой API-интерфейс API-интерфейса в python
  • «Плоский лучше, чем вложенный» - как для данных, так и для кода?
  • Где я могу получить SECRET_KEY для Flask?
  • Управление параметрами URL (Python Flask)
  • Python - лучший язык программирования в мире.