Более питонический способ запустить процесс X раз

90

Что более питоническое?

Пока цикл:

count = 0
while count < 50:
    print "Some thing"
    count = count + 1

Для цикла:

for i in range(50):
    print "Some thing"

Изменить: не дублировать, потому что у него есть ответы, чтобы определить, что яснее, или как запустить диапазон без `` i '' - хотя в итоге это оказалось самым элегантным

Лайонел
источник
8
Голосование «за» для компенсации голосов «против»: если Лайонел задаст этот вопрос, другие могут задать тот же вопрос, и ответы ниже будут полезны.
Эрик О Лебигот
2
Термин «Pythonic» используется слишком часто. Это синоним слов «читаемый» и «легко понятный». По крайней мере, на Python.
darioo
Возможный дубликат Можно ли реализовать цикл Python для диапазона без переменной итератора?
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

Ответы:

112

Лично:

for _ in range(50):
    print "Some thing"

если вам не нужно i. Если вы используете Python <3 и хотите повторять цикл много раз, используйте его, xrangeпоскольку нет необходимости заранее создавать весь список.

Феликс Клинг
источник
15
Однако следите за тем, чтобы _ был сопоставлен с функцией перевода gettext.
Гинтаутас Миляускас
Спасибо за этот ответ; это была основная причина, по которой я не использовал цикл for, потому что у меня была неиспользованная переменная в «i».
Lionel
6
_ такая же, как и любая другая переменная. Только в REPL это имеет какое-то особое значение. OP может также придерживаться i.
vezult
2
@vezult Мне это нравится, поскольку он дает понять, что переменная не используется в инструкции. Может быть, есть причина, которая затмевает это, чтобы придерживаться i?
ryanjdillon
6
Я твердо верю в добавление пони, особенно когда это звучит уместно ... для пони в диапазоне (50): print ("ржать") #python 3
Пол
3

Цикл for определенно более питоничен, поскольку он использует встроенную функциональность Python более высокого уровня, чтобы передать то, что вы делаете, более четко и лаконично. Накладные расходы на range vs xrange и назначение неиспользуемой iпеременной проистекают из отсутствия оператора, такого как оператор Verilog repeat. Основная причина, по которой следует придерживаться решения для диапазона, заключается в том, что другие способы более сложны. Например:

from itertools import repeat

for unused in repeat(None, 10):
    del unused   # redundant and inefficient, the name is clear enough
    print "This is run 10 times"

Использование повторения вместо диапазона здесь менее понятно, потому что это не так хорошо известная функция, и более сложное, потому что вам нужно ее импортировать. Основными руководствами по стилю, если вам нужна ссылка, являются PEP 20 - The Zen of Python и PEP 8 - Style Guide for Python Code .

Мы также отмечаем, что версия для диапазона является явным примером, используемым как в справочнике по языку, так и в учебнике , хотя в этом случае используется значение. Это означает, что форма должна быть более знакомой, чем расширение цикла for в стиле C.

Янн Вернье
источник
Не лучше ли использовать повторяющуюся вещь напрямую, например: for s in repeat('This is run 10 times', 10): print s??
F1Rumors
Безусловно! Но печать в образце кода была только примером повторяющегося участка кода, для которого может не быть центрального объекта.
Ян Вернье,
Разработчик ядра Python говорит, что это быстрее, чем использование range() twitter.com/raymondh/status/1144527183341375488
Chris_Rands
Это действительно быстрее, потому что не нужно искать или создавать разные intобъекты для каждой итерации. Однако время программиста может быть более ценным, чем время выполнения.
Ян Вернье
2

Если вам нужны побочные эффекты, возникающие внутри цикла, я лично выберу этот range()подход.

Если вам важен результат любых функций, которые вы вызываете в цикле, я бы пошел на понимание списка или mapподход. Что-то вроде этого:

def f(n):
    return n * n

results = [f(i) for i in range(50)]
# or using map:
results = map(f, range(50))
Кнутин
источник
results = (f for i in range (50))
Лука Ране
1
results = itertools.imap (f, range (50))
Лука Ране,
@ralu, только если вам не нужен повторный или произвольный доступ к результатам.
aaronasterling
2
result = tuple (results) и работает намного быстрее, чем list, поскольку нарезка кортежа составляет O (1)
Лука Ране
-3

Как насчет?

while BoolIter(N, default=True, falseIndex=N-1):
    print 'some thing'

или более уродливым способом:

for _ in BoolIter(N):
    print 'doing somthing'

или если вы хотите поймать последний раз через:

for lastIteration in BoolIter(N, default=False, trueIndex=N-1):
    if not lastIteration:
        print 'still going'
    else:
        print 'last time'

где:

class BoolIter(object):

    def __init__(self, n, default=False, falseIndex=None, trueIndex=None, falseIndexes=[], trueIndexes=[], emitObject=False):
        self.n = n
        self.i = None
        self._default = default
        self._falseIndexes=set(falseIndexes)
        self._trueIndexes=set(trueIndexes)
        if falseIndex is not None:
            self._falseIndexes.add(falseIndex)
        if trueIndex is not None:
            self._trueIndexes.add(trueIndex)
        self._emitObject = emitObject


    def __iter__(self):
        return self

    def next(self):
        if self.i is None:
            self.i = 0
        else:
            self.i += 1
        if self.i == self.n:
            raise StopIteration
        if self._emitObject:
            return self
        else:
            return self.__nonzero__()

    def __nonzero__(self):
        i = self.i
        if i in self._trueIndexes:
            return True
        if i in self._falseIndexes:
            return False
        return self._default

    def __bool__(self):
        return self.__nonzero__()
ОпасноМышь
источник
-5

На самом деле нет питонического способа что-то повторить. Однако это лучший способ:

map(lambda index:do_something(), xrange(10))

Если вам нужно передать индекс, тогда:

map(lambda index:do_something(index), xrange(10))

Учтите, что он возвращает результаты в виде коллекции. Так что, если вам нужно собрать результаты, это может помочь.

Аби М. Сангараб
источник
Это не только не лучше (накладные расходы на вызов функции, менее известные лямбда-выражения, сбор неиспользованных результатов в списке), 10 не является итерируемым.
Ян Вернье
Да, xrange (10), а не 10. Я сказал, что это лучше, потому что вам не нужно писать функцию или создавать цикл. Однако, как я уже сказал, настоящего питонического пути нет. Я изменил код, спасибо.
Аби М. Сангараб