У меня есть цикл, который хочет выполниться к исчерпанию или пока некоторый пользователь не указал, что предел достигнут. У меня есть конструкция, которая выглядит плохо все же, я, может казаться, не нахожу более изящный способ выразить ее; есть ли один?
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).
Может быть, что-то вроде этого было бы немного лучше:
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
Я бы начал с
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
Вы должны удалить вложенные ifs:
if predicate(i) and not limit is None:
...
Я бы внимательно посмотрел на библиотеку 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)
То, что вы хотите сделать, кажется, идеально подходит для цикла 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
или предел
достигает нуля.
Хм. Насколько я понимаю, предикат
просто вычисляется в сегментах, и вы полностью игнорируете его возвращаемое значение, верно?
Это еще один вариант:
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
из конца предиката
.