Bir İşlemi X Kez Çalıştırmanın Daha Fazla Pythonic Yolu


90

Hangisi daha pitonik?

Döngü sırasında:

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

Döngü için:

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

Düzenleme: Yinelenmez çünkü bu, hangisinin daha net olduğunu belirlemeye yönelik cevaplara sahiptir, buna karşılık 'i' olmadan bir aralığın nasıl çalıştırılacağına karşı - bu en zarif sonuç olsa bile


9
Olumsuz oyları telafi etmek için oylama: Lionel bu soruyu sorarsa, başkaları da aynı soruyu sorabilir ve aşağıdaki cevaplar faydalı olacaktır.
Eric O Lebigot

2
"Pythonic" terimi aşırı kullanılıyor. "Okunabilir" ve "kolayca anlaşılabilir" için bir eşanlamlı. En azından Python'da.
darioo

Yanıtlar:


115

Şahsen:

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

eğer ihtiyacın yoksa i. Python <3 kullanıyorsanız ve döngüyü birçok kez tekrarlamak istiyorsanız xrange, tüm listeyi önceden oluşturmanıza gerek olmadığı için kullanın.


15
Gettext çeviri işleviyle eşlenen _ olmasına dikkat edin.
Gintautas Miliauskas

Bu cevap için teşekkürler; bu, for-döngüsünü kullanmamamın ana sebebiydi çünkü "i" de kullanılmayan bir değişkenim vardı.
Lionel

6
_ tıpkı diğer değişkenler gibidir. Sadece REPL'de belirli bir önemi vardır. OP de devam edebilir i.
vezult

2
@vezult Değişkenin ifadede kullanılmadığını açıkça gösterdiği için bunu beğendim. Belki de buna bağlı kalmak için bunu gölgede bırakan bir neden var imı?
ryanjdillon

7
Midilli eklemeye kesinlikle inanıyorum, özellikle uygun göründüğünde ... menzil içindeki midilli için (50): print ("neigh") #python 3
Paul

3

For döngüsü kesinlikle daha pitoniktir, çünkü yaptığınız şeyi hem daha net hem de kısaca iletmek için Python'un daha yüksek seviyede yerleşik işlevselliğini kullanır. Xrange ve xrange arasındaki ek yük ve kullanılmayan bir ideğişkenin atanması , Verilog'un ifadesi gibi bir ifadenin olmamasından kaynaklanır repeat. For Range çözümüne bağlı kalmanın ana nedeni, diğer yolların daha karmaşık olmasıdır. Örneğin:

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"

Burada aralık yerine yinelemenin kullanılması daha az nettir çünkü bir işlev o kadar iyi bilinmemektedir ve daha karmaşıktır çünkü onu içe aktarmanız gerekir. Bir referansa ihtiyacınız varsa ana stil kılavuzları PEP 20 - The Zen of Python ve PEP 8 - Python Kodu için Stil Kılavuzu'dur .

Ayrıca aralığı için sürüm hem kullanılan açık örneğidir olduğuna dikkat dil referans ve öğretici bu durumda değer kullanılır rağmen,. Bu, formun bir C-stili for döngüsünün while genişlemesinden daha tanıdık olması gerektiği anlamına gelir.


Tekrarlanan şeyi doğrudan kullanmak daha iyi olmaz mıydı, yani: for s in repeat('This is run 10 times', 10): print s??
F1Rumors

Kesinlikle! Ancak örnek koddaki baskı, yalnızca merkezi bir nesne olmayabilecek tekrarlanan bir kod bölümünün bir örneğiydi.
Yann Vernier

Python çekirdek geliştiricisi bunun range() twitter.com/raymondh/status/1144527183341375488
Chris_Rands

Gerçekten daha hızlıdır çünkü inther yineleme için farklı bir nesne araması veya oluşturması gerekmez . Bununla birlikte, programcı zamanı yürütme süresinden daha değerli olabilir.
Yann Vernier

2

Döngü içinde meydana gelen yan etkilerin peşindeyseniz, kişisel olarak range()yaklaşıma giderim .

Döngü içinde çağırdığınız işlevlerin sonucunu önemsiyorsanız, bir liste anlayışına veya mapyaklaşımına giderim . Bunun gibi bir şey:

def f(n):
    return n * n

results = [f(i) for i in range(50)]
# or using map:
results = map(f, range(50))

sonuçlar = ((50) aralığındaki i için f)
Luka Rahne

1
sonuçlar = itertools.imap (f, range (50))
Luka Rahne

@ralu, yalnızca sonuçlara tekrarlanan veya rastgele erişime ihtiyacınız yoksa.
aaronasterling

2
sonuç = tuple (sonuçlar) ve listeden çok daha hızlı, çünkü tuple üzerinde dilimleme O (1)
Luka Rahne

-3

Nasıl olur?

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

veya daha çirkin bir şekilde:

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

veya son seferde:

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

nerede:

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

Bir şeyi tekrar etmenin gerçekten pitonik bir yolu yoktur. Ancak daha iyi bir yoldur:

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

Dizini geçmeniz gerekiyorsa, o zaman:

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

Sonuçları bir koleksiyon olarak döndürdüğünü düşünün. Dolayısıyla, sonuçları toplamanız gerekiyorsa, yardımcı olabilir.


Bu sadece daha iyi değil (işlev çağrısı ek yükü, daha az bilinen lambda ifadeleri, kullanılmayan sonuçları bir listede toplama), 10 tekrarlanabilir değildir.
Yann Vernier

Evet, xrange (10) değil 10. Daha iyi dedim çünkü bir fonksiyon yazmanıza veya bir döngü oluşturmanıza gerek yok. Ancak, dediğim gibi gerçek bir pitonik yol yok. Kodu değiştirdim, teşekkürler.
Abi M. Sangarab
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.