Uma maneira mais pitônica de executar um processo X Times

90

Qual é mais pitônico?

Loop While:

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

Para loop:

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

Editar: não duplicar porque tem respostas para determinar o que é mais claro, versus como executar um intervalo sem 'i' - mesmo que acabou sendo o mais elegante

Lionel
fonte
9
Votação positiva para compensar os votos negativos: se Lionel fizer esta pergunta, outras pessoas poderão fazer a mesma pergunta e as respostas abaixo serão úteis.
Eric O Lebigot
2
O termo "Pythônico" está sendo usado em demasia. É um sinônimo para "legível" e "facilmente compreensível". Em Python, pelo menos.
darioo
Possível duplicata de É possível implementar um loop Python for range sem uma variável iteradora?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respostas:

115

Pessoalmente:

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

se você não precisa i. Se você usa Python <3 e deseja repetir o loop muitas vezes, use, xrangepois não há necessidade de gerar a lista inteira de antemão.

Felix Kling
fonte
15
No entanto, esteja atento para _ ser mapeado para a função de tradução gettext.
Gintautas Miliauskas
Obrigado por esta resposta; esse era o principal motivo pelo qual eu não estava usando o loop for porque tinha uma variável não usada em "i".
Lionel
6
_ é como qualquer outra variável. É apenas no REPL que tem algum significado particular. O OP pode muito bem continuar i.
vezult
2
@vezult Gosto disso porque deixa claro que a variável não está sendo usada na instrução. Existe talvez uma razão que ofusque isso para ficar com o i?
ryanjdillon
7
Eu acredito firmemente na adição de pôneis, especialmente quando parece apropriado ... para pôneis no intervalo (50): print ("neigh") #python 3
Paul
3

O loop for é definitivamente mais pythônico, pois usa a funcionalidade integrada de nível superior do Python para transmitir o que você está fazendo de forma mais clara e concisa. A sobrecarga de range vs xrange, e atribuição de uma ivariável não usada , resulta da ausência de uma declaração como a de Verilog repeat. A principal razão para seguir a solução de intervalo for é que outras formas são mais complexas. Por exemplo:

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"

Usar repetir em vez de intervalo aqui é menos claro porque não é uma função tão conhecida e mais complexo porque você precisa importá-la. Os principais guias de estilo, se você precisar de uma referência, são PEP 20 - O Zen do Python e PEP 8 - Guia de estilo para código Python .

Também observamos que a versão do intervalo for é um exemplo explícito usado na referência de linguagem e no tutorial , embora, nesse caso, o valor seja usado. Isso significa que a forma está fadada a ser mais familiar do que a expansão while de um loop for estilo C.

Yann Vernier
fonte
Não seria melhor usar a coisa repetida diretamente, ou seja: for s in repeat('This is run 10 times', 10): print s??
F1Rumors de
Certamente! Mas a impressão no código de amostra foi apenas um exemplo de uma seção repetida de código, para a qual pode não haver um objeto central.
Yann Vernier
O desenvolvedor principal do Python diz que isso é mais rápido do que usar range() twitter.com/raymondh/status/1144527183341375488
Chris_Rands
Na verdade, é mais rápido, porque não precisa procurar ou criar um intobjeto diferente para cada iteração. No entanto, o tempo do programador pode ser mais valioso do que o tempo de execução.
Yann Vernier
2

Se você estiver atrás dos efeitos colaterais que acontecem dentro do loop, eu pessoalmente escolheria o range() abordagem.

Se você se preocupa com o resultado de quaisquer funções que você chama dentro do loop, eu optaria por uma compreensão de lista ou mapabordagem. Algo assim:

def f(n):
    return n * n

results = [f(i) for i in range(50)]
# or using map:
results = map(f, range(50))
Knutin
fonte
resultados = (f para i no intervalo (50))
Luka Rahne
1
resultados = itertools.imap (f, intervalo (50))
Luka Rahne
@ralu, apenas se você não precisar de acesso repetido ou aleatório aos resultados.
aaronasterling
2
resultado = tupla (resultados) e é muito mais rápido do que a lista, já que o corte na tupla é O (1)
Luka Rahne
-3

E se?

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

ou de uma forma mais feia:

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

ou se você quiser pegar a última vez por meio de:

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

Onde:

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__()
DangerMouse
fonte
-5

Não existe uma maneira realmente pitônica de repetir algo. No entanto, é uma maneira melhor:

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

Se você precisar passar no índice:

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

Considere que ele retorna os resultados como uma coleção. Portanto, se você precisar coletar os resultados, isso pode ajudar.

Abi M.Sangarab
fonte
Além de não ser realmente melhor (sobrecarga de chamada de função, expressões lambda menos conhecidas, coleta de resultados não utilizados em uma lista), 10 não é iterável.
Yann Vernier
Sim, xrange (10) não 10. Eu disse que é melhor porque você não precisa escrever uma função ou fazer um loop. No entanto, como eu disse, não existe um caminho python real. Eu mudei o código, obrigado.
Abi M.Sangarab