больше pythonic способа выразить условно ограниченный цикл?

У меня есть цикл, который хочет выполниться к исчерпанию или пока некоторый пользователь не указал, что предел достигнут. У меня есть конструкция, которая выглядит плохо все же, я, может казаться, не нахожу более изящный способ выразить ее; есть ли один?

def ello_bruce(limit=None):
    for i in xrange(10**5):
        if predicate(i):
            if not limit is None:
                limit -= 1
                if limit <= 0:
                   break

def predicate(i):
    # lengthy computation
    return True

Святое вложение! Должен быть лучший путь. В целях рабочего примера, xrange используется, где у меня обычно есть итератор конечной но неизвестной длины (и предикат иногда возвращает False).

5
задан msw 26 April 2010 в 05:31
поделиться

6 ответов

Может быть, что-то вроде этого было бы немного лучше:

from itertools import ifilter, islice

def ello_bruce(limit=None):
    for i in islice(ifilter(predicate, xrange(10**5)), limit):
        # do whatever you want with i here
11
ответ дан 18 December 2019 в 11:54
поделиться

Я бы начал с

if limit is None: return

, поскольку ничего не может случиться с пределом , когда он начинается как Нет (если нет желаемых побочных эффектов в итерации и при вычислении предиката - если есть, то в этом случае вы можете просто выполнить для i в xrange (10 ** 5 ): предикат (i) ).

Если limit не равен None , тогда вы просто хотите выполнить max (limit, 1) вычислений предиката , которые правда, поэтому itertools.islice из itertools.ifilter подойдет:

import itertools as it

def ello_bruce(limit=None):
    if limit is None:
        for i in xrange(10**5): predicate(i)
    else:
        for _ in it.islice(
          it.ifilter(predicate, xrange(10**5),
          max(limit, 1)): pass
1
ответ дан 18 December 2019 в 11:54
поделиться

Вы должны удалить вложенные ifs:

if predicate(i) and not limit is None:
    ...
1
ответ дан 18 December 2019 в 11:54
поделиться

Я бы внимательно посмотрел на библиотеку itertools . Используя это, я думаю, у вас будет что-то вроде ...

# From the itertools examples
def tabulate(function, start=0):
    return imap(function, count(start))
def take(n, iterable):
    return list(islice(iterable, n))

# Then something like:
def ello_bruce(limit=None):
  take(filter(tabulate(predicate)), limit)
2
ответ дан 18 December 2019 в 11:54
поделиться

То, что вы хотите сделать, кажется, идеально подходит для цикла while:

def ello_bruce(limit=None):
    max = 10**5
    # if you consider 0 to be an invalid value for limit you can also do
    # if limit:
    if limit is None: 
        limit = max

    while max and limit:
        if predicate(i):
            limit -= 1
        max -=1

Цикл останавливается, если max или предел достигает нуля.

0
ответ дан 18 December 2019 в 11:54
поделиться

Хм. Насколько я понимаю, предикат просто вычисляется в сегментах, и вы полностью игнорируете его возвращаемое значение, верно?

Это еще один вариант:

import itertools

def ello_bruce(limit=None):
    if limit is None:
        limiter= itertools.repeat(None)
    else:
        limiter= xrange(limit)

    # since predicate is a Python function
    # itertools looping won't be faster, so use plain for.
    # remember to replace the xrange(100000) with your own iterator
    for dummy in itertools.izip(xrange(100000), limiter):
        pass

Кроме того, удалите ненужный return True из конца предиката.

0
ответ дан 18 December 2019 в 11:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: