2013-02-06 4 views
27

Angeregt durch die Diskussion hereIst das Shortcircuit-Verhalten von Pythons Any/All explizit?

Die docs vorschlagen einigen entsprechenden Code für das Verhalten von all und any

Sollte das Verhalten des äquivalenten Code Teil der Definition in Betracht gezogen werden, oder kann sie eine Implementierung umzusetzen in einem Nicht-Kurzschluss-Art?

Hier ist der relevante Auszug aus CPython/Lib/test/test_builtin.py

def test_all(self): 
    self.assertEqual(all([2, 4, 6]), True) 
    self.assertEqual(all([2, None, 6]), False) 
    self.assertRaises(RuntimeError, all, [2, TestFailingBool(), 6]) 
    self.assertRaises(RuntimeError, all, TestFailingIter()) 
    self.assertRaises(TypeError, all, 10)    # Non-iterable 
    self.assertRaises(TypeError, all)     # No args 
    self.assertRaises(TypeError, all, [2, 4, 6], []) # Too many args 
    self.assertEqual(all([]), True)      # Empty iterator 
    S = [50, 60] 
    self.assertEqual(all(x > 42 for x in S), True) 
    S = [50, 40, 60] 
    self.assertEqual(all(x > 42 for x in S), False) 

def test_any(self): 
    self.assertEqual(any([None, None, None]), False) 
    self.assertEqual(any([None, 4, None]), True) 
    self.assertRaises(RuntimeError, any, [None, TestFailingBool(), 6]) 
    self.assertRaises(RuntimeError, all, TestFailingIter()) 
    self.assertRaises(TypeError, any, 10)    # Non-iterable 
    self.assertRaises(TypeError, any)     # No args 
    self.assertRaises(TypeError, any, [2, 4, 6], []) # Too many args 
    self.assertEqual(any([]), False)     # Empty iterator 
    S = [40, 60, 30] 
    self.assertEqual(any(x > 42 for x in S), True) 
    S = [10, 20, 30] 
    self.assertEqual(any(x > 42 for x in S), False) 

Es hat nichts tun das Kurzschlussverhalten

+0

Interessant, dass die Testsuite keinen Kurzschluss erzwingt. Scheint mir ein Versehen. Ich behaupte immer noch, dass Kurzschlüsse Teil der Spezifikation sind. – mgilson

+4

Ich habe einen Fehler im Code entdeckt, den Sie gepostet und [ein Problem] abgelegt haben (http://bugs.python.org/issue17142). – Sjoerd

+4

Ich habe auch [eine Ausgabe] (http://bugs.python.org/issue17255) für das betreffende Verhalten eingereicht. – wim

Antwort

30

Das Verhalten ist garantiert. Ich habe kürzlich eine patch beigetragen, die akzeptiert wurde und merged, also, wenn Sie die neuesten Quellen greifen, werden Sie sehen, dass das Kurzschlussverhalten jetzt explizit erzwungen wird.

git clone https://github.com/python/cpython.git 
grep Short-circuit cpython/Lib/test/test_builtin.py 
+4

Es macht immer Spaß zu sehen, wie sich das Schlachtfeld in die Elfenbeintürme bewegt. ; ^) – DSM

+7

Es ist wunderbar, die Zeitleiste zu dieser Frage zu sehen: Am 13. Februar wird die Frage gestellt, am 14. Februar gibt es die [erste Revision] (http://stackoverflow.com/revisions/14866380/1) dieser Antwort, 20. Februar der [bug/patch] (http://bugs.python.org/issue17255) wird erstellt, am 21. Februar wird er zusammengeführt und am 23. Februar wird diese Antwort aktualisiert. Dank dieser Frage zu Stack Overflow ist die Python-Bibliothek besser geworden. (Danke an dich @wim natürlich.) – ShreevatsaR

9

Die docs sagen

zu erzwingen "Gibt True zurück, wenn ein Element des Iterablen Wahr ist. Wenn das Iterable leer ist, gebe False zurück. ÄQUIVALENT:" (Hervorhebung von mir) ...

def any(iterable): 
    for element in iterable: 
     if element: 
      return True 
    return False 

Wenn any nicht Kurzschluss täte, würde es nicht klar Kurzschlüssen seit dem entsandten Code GLEICHWERTIGEN für den entsandten Code sein. Sie könnten beispielsweise mehr von einem Generator verbrauchen als Sie möchten. Angesichts dessen sage ich, dass das Kurzschlussverhalten garantiert ist.

Das exakt gleiche Argument könnte für all gemacht werden.

+0

Dies ist mein Verständnis zu. Es wird interessant sein zu sehen, welche Gegenargumente vorgebracht werden. –

+2

@gnibbler - Ich glaube nicht, dass es Gegenargumente geben wird (außer vielleicht von Simon in Ihrem ursprünglichen Post). Soweit es mich betrifft, ist dies ein klar dokumentiertes Verhalten ... – mgilson

+0

@gnibbler - Wenn Sie interessante Diskussionen über die Implementierung suchen, lesen Sie die Kommentare zu 'exec' vs.' localhips' zwischen mir, MartijnPieters und DSM, die [hier] (http://stackoverflow.com/a/14697234/748858) gestartet und [hier] gelandet ist (http://stackoverflow.com/a/14716991/748858) – mgilson

0

Es muss kurzgeschlossen werden, da es eine ungebundene iterable gegeben werden könnte. Wenn es nicht Kurzschluss hat dann wäre dies niemals enden:

any(x == 10 for x in itertools.count()) 
+2

Ich glaube nicht, dass dieses Beispiel beweist, dass es einen Kurzschluss hat. Sie können solche Anweisungen schreiben, die nie ganz einfach enden und Python gibt Ihnen die Freiheit, das zu tun: 'any (x == -1000 für x in itertools.count())' – mgilson

+0

@mgilson Aber nicht kurzschließen ändert ein Programm (Fragment) von beenden zu nicht enden. Python gibt Ihnen auch die Möglichkeit, die Ausgabe zu drucken, aber das bedeutet nicht, dass die Ganzzahleingabe das Ergebnis drucken kann. – delnan

+2

Nicht enden in diesem Fall würde saugen - und machen alle weniger sinnvoll. Meine Frage ist, ob oder nicht die Python-Sprache _ es erfordert, um es zu beenden. –

Verwandte Themen