Frage

Ich arbeite mit Generator-Funktionen und privaten Funktionen einer Klasse. Ich frage mich,

  1. Warum bei Nachgeben (was in meinem Fall ein Zufall war) in __someFunc, dass diese Funktion erscheint einfach nicht aus __someGenerator aufgerufen werden. Auch was ist die Terminologie ich verwenden soll, wenn auf diese Aspekte der Sprache beziehen?
  2. Können die Python-Interpreter von solchen Fällen warnen?

Im Folgenden ist ein Beispiel Ausschnitt aus meinem Szenario.

class someClass():
    def __init__(self):
        pass

    #Copy and paste mistake where yield ended up in a regular function
    def __someFunc(self):
        print "hello"
        #yield True #if yielding in this function it isn't called

    def __someGenerator (self):
        for i in range(0, 10):
            self.__someFunc()
            yield True
        yield False

    def someMethod(self):
        func = self.__someGenerator()
        while func.next():
            print "next"

sc = someClass()
sc.someMethod()

habe ich auf diese verbrannt und damit verbracht, einige Zeit, um herauszufinden, warum eine Funktion war einfach nicht genannt zu werden. Ich schließlich entdeckte ich in der Funktion Nachgeben ich nicht wollte in.

War es hilfreich?

Lösung

Ich werde versuchen, die ersten Ihre Fragen zu beantworten.

Eine reguläre Funktion, wenn wie folgt aufgerufen:

val = func()

führt seine Innenseite Aussagen bis zum Ende oder eine return Anweisung erreicht ist. Dann wird der Rückgabewert der Funktion val zugeordnet ist.

Wenn ein Compiler erkennt die Funktion tatsächlich ein Generator sein und nicht eine reguläre Funktion (es durch die Suche nach yield Aussagen innerhalb der Funktion ist, dass - wenn es mindestens einen, es ist ein Generator), das Szenario, wenn es den Aufruf gleiche Art und Weise wie oben hat unterschiedliche Folgen. Nach func() Aufruf kein Code innerhalb der Funktion ausgeführt , und ein spezieller <generator> Wert wird auf val zugeordnet. Dann wird das erste Mal, wenn Sie val.next() nennen, die tatsächlichen Angaben von func werden, bis ein yield oder return ausgeführt angetroffen wird, auf denen die Ausführung der Funktion stoppt, Wert ergab zurückgegeben und Generator wartet auf einen anderen Anruf val.next().

Aus diesem Grund, in Ihrem Beispiel Funktion __someFunc nicht „Hallo“ gedruckt wird - seine Aussagen nicht ausgeführt wurden, weil Sie nicht self.__someFunc().next(), sondern nur self.__someFunc()

genannt haben.

Leider bin ich ziemlich sicher, dass es keine ist eingebauter Warnmechanismus für Programmierfehler wie bei Ihnen.

Andere Tipps

Ein „Generator“ ist nicht so sehr eine Sprache-Funktion, als Name für Funktionen, die „Ausbeute“. Nachgeben ist so ziemlich immer legal. Es gibt nicht wirklich eine Möglichkeit für Python zu wissen, dass Sie nicht die „mittleren“ von einer Funktion zu erhalten.

Dieser PEP http://www.python.org/dev/peps/pep -0255 / spricht über Generatoren, und kann Ihnen helfen, den Hintergrund besser zu verstehen.

Ich sympathisiere mit Ihrer Erfahrung, aber Compiler können nicht herausfinden, was Sie „bedeutet für sie zu tun“, nur das, was Sie sagten ihnen, tatsächlich zu tun.

Python weiß nicht, ob Sie ein Generator-Objekt für eine spätere Iteration erstellen möchten oder eine Funktion aufrufen. Aber Python ist nicht Ihre einzige Werkzeug für zu sehen, was mit Ihrem Code vor sich geht. Wenn Sie einen Editor oder IDE verwenden, die benutzerdefinierte Syntax-Hervorhebung ermöglicht, können Sie es sagen, die Ausbeute Schlüsselwort eine andere Farbe zu geben, oder sogar einen hellen Hintergrund, mit dem Sie Ihre Fehler schneller finden helfen, zumindest. In vim, zum Beispiel, könnten Sie tun:

:syntax keyword Yield yield
:highlight yield ctermbg=yellow guibg=yellow ctermfg=blue guifg=blue

Das sind schrecklichen Farben, nebenbei bemerkt. Ich empfehle Kommissionierung etwas besser. Eine weitere Option, wenn Ihr Editor oder IDE nicht kooperieren, ist eine benutzerdefinierte Regel in einem Code-Checker wie Pylint einzurichten. Ein Beispiel aus Pylint der Quellkodearchivs:

from pylint.interfaces import IRawChecker
from pylint.checkers import BaseChecker

class MyRawChecker(BaseChecker):
    """check for line continuations with '\' instead of using triple
    quoted string or parenthesis
    """

    __implements__ = IRawChecker

    name = 'custom_raw'
    msgs = {'W9901': ('use \\ for line continuation',
                     ('Used when a \\ is used for a line continuation instead'
                      ' of using triple quoted string or parenthesis.')),
           }
    options = ()

    def process_module(self, stream):
        """process a module

        the module's content is accessible via the stream object
        """
        for (lineno, line) in enumerate(stream):
            if line.rstrip().endswith('\\'):
                self.add_message('W9901', line=lineno)


def register(linter):
    """required method to auto register this checker"""
    linter.register_checker(MyRawChecker(linter))

Die Pylint Handbuch finden Sie hier: http://www.logilab.org/card/pylint_manual Und Syntax Dokumentation des vim ist hier: http://www.vim.org/htmldoc/syntax.html

Da das return Schlüsselwort beide anwendbar in Generator Funktionen und regelmäßigen Funktionen, gibt es nichts, was Sie möglicherweise überprüfen könnten (wie @Christopher erwähnt). Das return Schlüsselwort in einem Generator zeigt an, dass eine StopIteration Ausnahme ausgelöst werden soll.

Wenn Sie versuchen, aus einem Generator mit einem Wert return (was keinen Sinn macht, da return nur bedeutet „Iteration stoppen“), wird der Compiler bei der Kompilierung-Zeit beschweren - dies kann einige fangen Kopieren und -Paste Fehler:

>>> def foo():
...     yield 12
...     return 15
... 
  File "<stdin>", line 3
SyntaxError: 'return' with argument inside generator

Ich persönlich rate nur gegen Kopieren und Einfügen-Programmierung. : -)

Von dem PEP:

  

Beachten Sie, dass Rückkehr bedeutet: „Ich bin fertig, und haben nichts interessant   return“für beide Generatorfunktionen und nicht-Generator-Funktionen.

Wir tun dies.

Generatoren haben Namen mit „erzeugen“ oder „gen“ in ihrem Namen. Es wird eine Ertragsrechnung im Körper hat. Ziemlich einfach visuell zu überprüfen, da keine Methode viel mehr als 20 Zeilen Code ist.

Andere Methoden haben nicht "gen" in ihrem Namen.

Auch wir tun nicht jedem Gebrauch __ (Doppelstrich) Namen unter keinen Umständen. 32.000 Zeilen Code. Nicht __ Namen.

Die "Generator vs. nicht-Generator" Methode Funktion ist vollständig ein Design Frage. Was hat der Programmierer „beabsichtigen“ geschehen. Der Compiler kann Ihre Absicht nicht leicht zu validieren, kann es nur bestätigen, was Sie tatsächlich eingegeben hat.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top