2017-11-02 4 views
2

Die folgende Methode ist in meiner Klasse und versucht, sich selbst zu primen, bevor ihre Arbeit erledigt wird. Der Primer ist faul beim Ausführen seiner Arbeit als die Verarbeitungsschleife, die ihm folgt. In diesen beiden Schleifen wiederholen sich fünf Zeilen, und mir ist nicht klar, was der beste Weg zur Beseitigung der Wiederholung sein könnte.Gibt es eine Möglichkeit, diesen Generator zu trocknen?

Gibt es eine effektive und klare Möglichkeit, diese letzten fünf Zeilen nur einmal in der Klasse oder Methode zu schreiben?


Nachtrag

In Antwort auf die Frage, was prefix und suffix sind, hier ist die Deque Klasse:

class Deque(collections.deque): 
    """Deque([iterable[, maxlen]]) -> Deque instance""" 

    @property 
    def prefix(self): 
     """Property allowing capture of all but last item in deque.""" 
     item = self.pop() 
     value = tuple(self) 
     self.append(item) 
     return value 

    @property 
    def suffix(self): 
     """Property allowing capture of all but first item in deque.""" 
     item = self.popleft() 
     value = tuple(self) 
     self.appendleft(item) 
     return value 

Zweite Version

Nach Berücksichtigung, was andere hatten die folgende Methode zu sagen, für Effizienz geschrieben wurde:

@classmethod 
def __get_start_words(cls, iterable, n, start_words): 
    iterator, buffer, count = iter(iterable), Deque(maxlen=n), 0 
    for item, count in zip(iterator, range(n)): 
     buffer.append(item) 
     yield item 
    if count + 1 < n: 
     raise ValueError('iterable was too short to satisfy n') 
    start_words[buffer.prefix] += 1 
    try: 
     while True: 
      if buffer[0][-1] in cls.TERMINATORS: 
       start_words[buffer.suffix] += 1 
      item = next(iterator) 
      buffer.append(item) 
      yield item 
    except StopIteration: 
     pass 

dritte Version

von Daniel Diese dritte Version des Verfahrens angepasst wurde ‚s interessante Antwort:

@classmethod 
def __get_start_words(cls, iterable, n, start_words): 
    count, buffer = 0, Deque(maxlen=n) 
    for count, item in enumerate(iterable, 1): 
     yield item 
     buffer.append(item) 
     if count == n: 
      start_words[buffer.prefix] += 1 
     if count >= n and buffer[0][-1] in cls.TERMINATORS: 
      start_words[buffer.suffix] += 1 
    if count < n: 
     raise ValueError('iterable was too short to satisfy n') 

Final Version

Diese Methode ist deutlich besser als meine erste Version - dank der Menschen, die mir hier geholfen.

@classmethod 
def __get_start_words(cls, iterable, n, start_words): 
    buffer = Deque(maxlen=n) 
    for count, item in enumerate(iterable, 1): 
     yield item 
     buffer.append(item) 
     if count == n: 
      start_words[buffer.prefix] += 1 
     if count >= n and buffer[0][-1] in cls.TERMINATORS: 
      start_words[buffer.suffix] += 1 
    if len(buffer) < n: 
     raise ValueError('iterable was too short to satisfy n') 
+0

BTW, was ist 'buffer.prefix' und' buffer.suffix'? – quamrana

+0

Ich habe mich entschieden, in der ersten Schleife eine logische Überprüfung durchzuführen, indem ich eine Ausnahme aufrufe. Wenn die Änderung die Frage ungültig macht, lösche ich sie gerne. –

+1

wahrscheinlich eine bessere Frage für SE: codereview – Aaron

Antwort

4

Verwenden for -loop:

@classmethod 
def __get_start_words(cls, iterable, n, start_words): 
    buffer = Deque(maxlen=n) 
    for idx, item in enumerate(iterable, 1): 
     buffer.append(item) 
     yield item 
     if idx == n: 
      start_words[buffer.prefix] += 1 
     if idx >= n and buffer[0][-1] in cls.TERMINATORS: 
      start_words[buffer.suffix] += 1 
    if len(buffer) < n: 
     raise ValueError('iterable was too short to satisfy n') 

Einige Gedanken auf Ihre zweite Version: count nicht notwendig ist, wenn islice mit:

for item in islice(iterator, n): 
    buffer.append(item) 
    yield item 
if len(buffer) < n: 
    raise ValueError('iterable was too short to satisfy n') 

Weitere Refactoring zu Folgendem führen:

@classmethod 
def __get_start_words(cls, iterable, n, start_words): 
    iterable = iter(iterable) 
    buffer = deque(islice(iterable, n-1)) 
    yield from buffer 
    if len(buffer) < n - 1: 
     raise ValueError('iterable was too short to satisfy n') 
    start_words[tuple(buffer)] += 1 
    for item in iterable: 
     buffer.append(item) 
     yield item 
     first = buffer.popleft() 
     if first[-1] in cls.TERMINATORS: 
      start_words[tuple(buffer)] += 1 
+0

Danke für den Vorschlag! Nachdem ich den Code angeschaut hatte, erkannte ich, dass eine Fehlerüberprüfung durchgeführt werden sollte und änderte die erste Schleife, indem eine Ausnahme ausgelöst wurde, anstatt zu brechen. Würde es Ihnen etwas ausmachen, Ihre bereits gut geschriebene Antwort für den Ausnahmefall anzupassen? –

+0

Wenn Sie denken, dass es keinen Grund gibt, meinen Code für Verbesserungen zu ändern, da er modifiziert wurde, um eine Ausnahme auszulösen (kein Grund, ihn auszutrocknen), lassen Sie es mich wissen, und ich werde den Code zurücksetzen, statt "break" zu verwenden 'heben' auf, wie es vorher war. –

+0

@NoctisSkytower das ist im Grunde, wie ich es angehen würde. Es sieht so aus, als ob Sie nur versucht haben, For-Schleifen mit einem benutzerdefinierten 'raise StopIteration'-Ansatz zu replizieren. – Aaron

Verwandte Themen