8

Bir "mantık bulmacasını" çözmek için basit bir betik yazdım, okuldan bir takım kuralların verildiği bir bulmaca türü var ve o zaman problemler için çözüm bulmalıyım. "A, B adlı beş müzisyen var. Bir konserde oynayan C, D ve E, her biri birbiri ardına oynar ... Eğer A, B'den önce gelirse ve D son değil ... Kimin ne zaman oynar? vbKısa devre ile fonksiyonların/ifadelerin bir listesini değerlendirmek için bir Python deyim var mı?

Ben örnek

#Fifth slot must be B or D 
def rule1(solution): 
    return solution[4] == 'B' or solution[4] == 'D' 

#There must be at least two spots between A and B 
def rule2(solution): 
    returns abs(solution.index('A') - solution.index('B')) >= 2 

#etc... 

Ben, (dizeleri bir liste olarak basitçe gösterilen) bir olası çözüm geçerli olup olmadığını değerlendirmek olurdu ayrı bir fonksiyonu olarak her bir "kural" yazdınız olası çözümleri değerlendirmek Olası bir çözümün tüm bu kuralları geçip geçmediğini test etmek için Pythonic yolunu bulmakla ilgileniyorum, ilk başarısızlıktan sonra kuralları değerlendirmeyi bırakma becerisi.

İlk başta ben mümkün olan en basit şeyi yazdım:

def is_valid(solution): 
    return rule1(solution) and rule2(solution) and rule3(solution) and ... 

Ama bu oldukça çirkin görünüyordu. O, ben ... Bunun bir liste anlayışı gibi bir şey ile biraz daha zarif okumak yapabiliriz belki

def is_valid(solution) 
    rules = [rule1, rule2, rule3, rule4, ... ] 
    return all([r(solution) for f in rules]) 

düşündü ... ama sonra liste anlama all() işlevi önce oluşturulan beri değerlendirilir fark Bu, hiç de kısa devre olmadığının yan etkisine sahiptir - ilk kurallar False ilk versiyse bile her kural değerlendirilecektir.

Yani benim soru: kısa devre edildiği, True/False ifadelerin listesini değerlendirmek edebilmek için daha Pythonic/işlevsel yolu return f1(s) and f2(s) and f3(s) ... uzun bir listesini yazmaya gerek kalmadan, var mı?

cevap

13

kullanın generator expression:

rules = [ rule1, rule2, rule3, rule4, ... ] 
rules_generator = (r(solution) for r in rules) 
return all(rules_generator) 

Sözdizimsel şeker:

rules = [ rule1, rule2, rule3, rule4, ... ] 
return all(r(solution) for r in rules) 

Bir jeneratör (temelde) olan bir sonraki öğeyi döndüren bir .next() yöntemle bir nesne,: ekstra parantez atlayabilirsiniz bazı yinelenebilir. Bu, tüm dosyaları belleğe yüklemeden veya büyük tamsayılara kadar yinelemeden bir dosyada okumak gibi yararlı şeyler yapabileceği anlamına gelir. Saydam bir şekilde for döngüleri üzerinden bunları yineleyebilirsiniz; Python onu sahne arkasına işliyor. Örneğin, range, Py3k'de bir üreticidir.

def integers(): 
    i = 0 
    while True: 
     yield i 

ve Python vb işlevin durumunu tasarruf işlemek ve edecektir:

Bir işlev tanımında yield deyimi yerine return kullanarak kendi özel jeneratör ifadeleri geri alabilirsiniz. Onlar harikalar!

+1

Buradaki temel fark, köşeli parantezleri içermezken, tümü ([r (çözüm) için kurallar için])), böylece tüm() 'nin değerlendirilmesinden önce tüm sonuçların bir listesini oluşturmaz. –

+2

Evet. Her iki durumda da "all" argümanı geçilmeden önce değerlendirilir, ancak liste kavramasının değerlendirilmesi tüm listeyi hafızada oluştururken, bir generatör ifadesini değerlendirmek elemanları talep üzerine yükleyen bir jeneratör nesnesi oluşturur. – katrielalex

+0

Mükemmel, bu çok mantıklı - teşekkürler –

İlgili konular