Komma-formatierter Listendrucker

Oct 31 2020

Ich arbeite an einem Listenübungsprojekt aus dem Buch "Automate the Boring Stuff with Python", das dies verlangt:

Schreiben Sie eine Funktion, die einen Listenwert als Argument verwendet und eine Zeichenfolge zurückgibt, bei der alle Elemente durch ein Komma und ein Leerzeichen getrennt sind und vor dem letzten Element eingefügt werden. Wenn Sie beispielsweise die vorherige Spam-Liste an die Funktion übergeben, werden "Äpfel, Bananen, Tofu und Katzen" zurückgegeben. Ihre Funktion sollte jedoch mit jedem an sie übergebenen Listenwert arbeiten können. Testen Sie unbedingt den Fall, in dem eine leere Liste [] an Ihre Funktion übergeben wird.

Bisher habe ich mir Folgendes ausgedacht:

def comma_code(iterable):
    '''
    Function that loops through every value in a list and prints it with a comma after it,
    except for the last item, for which it adds an "and " at the beginning of it.
    Each item is str() formatted in output to avoid concatenation issues.

    '''
    for i, item in enumerate(iterable):
        if i == len(iterable)-1 and len(iterable) != 1: # Detect if the item is the last on the list and the list doesn't contain only 1 item (BONUS) 
            print('and ' + str(iterable[-1]))           # Add 'and ' to the beginning
        elif len(iterable) == 1:                        # BONUS: If list contains only 1 item,
            print('Just ' + str(iterable[-1]))          # replace 'and ' with 'Just '
        else:                                           # For all items other than the last one
            print(str(iterable[i]) + ',', end=" ")      # Add comma to the end and omit line break in print

Es gibt viele Kommentare, weil ich ziemlich neu bin und versuche, alles so klar wie möglich für mein zukünftiges Selbst zu lassen.

Jetzt frage ich mich, ob es einen besseren Weg gibt, dies zu tun, und auch (subjektive Frage), ob mein Code etwas enthält, das ich zur besseren Lesbarkeit und / oder zum besseren Stil ändern sollte. Wie gesagt, ich bin ziemlich neu und möchte von Anfang an gute Codierungspraktiken auswählen.

Dies sind einige Listen, die ich durch die Funktion geführt habe:

spam = ['apples', 'bananas', 'tofu', 'cats']
bacon = [3.14, 'cat', 11, 'cat', True]
enty = [1]

Und das ist die Arbeitsleistung:

apples, bananas, tofu, and cats
3.14, cat, 11, cat, and True
Just 1

Danke im Voraus.

Antworten

9 AryanParekh Oct 31 2020 at 19:55

Ein alternativer Ansatz

  • Die Routine ist für alle Arten von Eingaben gleich, außer wenn die len(list) == 1. Aus diesem Grund können wir eine Generatorfunktion verwenden , um die Routine zu vereinfachen, und dann eine einfache ifAnweisung, um mit der Ausnahme zu arbeiten
def comma_code(iterable):
    result = ', '.join(str(value) for value in iterable[:-1])
    return f"{result}, and {iterable[-1]}"

Da wir uns nun mit einem Sonderfall befassen müssen, kann eine if-Anweisung funktionieren

def comma_code(iterable):
    if not iterable: return None
    if len(iterable) == 1: return f"Just {iterable[0]}"

    result = ', '.join(str(value) for value in iterable[:-1])
    return f"{result}, and {iterable[-1]}"

Die Frage hat nicht angegeben, was zu tun ist, wenn die Größe des Containers ist 0, daher bin ich gerade zurückgekehrt None. Wie von @Stef in den Kommentaren angegeben, können Sie auch eine leere Zeichenfolge zurückgeben, die nur ist ''.
Ich würde es vorziehen, Nonewenn es einfach wird, zurück zu verfolgen, wenn ein Problem aufgetreten ist.
Darüber hinaus können Sie auch eine einfache Funktion entwerfen, mit der überprüft wird, ob der Container leer ist. Wenn dies der Fall ist, kann die Funktion eine benutzerdefinierte Warnung drucken, die Ihnen beim Debuggen Ihres Codes helfen kann

Erläuterung

result = ', '.join(str(value) for value in iterable[:-1])

Dies wird eine gerufene Generatorfunktion , sind wir grundsätzlich anhängen str(value) + ', 'für jeden valuein iterable.
iterable[:-1]so dass wir nur bis zum vorletzten Element iterieren.
Um vollständig wortreich zu sein, :-1sagt alles iterablebis zum letzten Element


6 hc_dev Oct 31 2020 at 19:57

Gut gemacht

Zuerst mag ich deine Einstellung "für die Zukunft ich". Behalten Sie diese saubere Codierungspraxis bei. Es wird wirklich helfen.

Randkoffer beiseite legen

Ich würde den Verbindungsteil (",", "und") und insbesondere den Einzelfall ("Nur") extrahieren :

def print_joined(iterable):
  # in unlikely case of nothing (fail-fast)
  if len(iterable) == 0:
    # raise an error or print sorry instead of returning silently
    return
  # special intro if single
  elif len(iterable) == 1:
    print('Just ' + str(iterable[0]))
    return

  ## multiples concatenated
  for i, item in enumerate(iterable):
      join = ', ' # default separator

  ## multiples concatenated
  joined_items = ''
  for i, item in enumerate(iterable):
      junction = ', ' # default separator

      if i == len(iterable)-2:
        junction = ' and ' # special separator before last
      elif i == len(iterable)-1:
        junction = ''  # last item ends without separator

      joined_items += str(item) + junction  # you defined item on loop, so use it

  print(joined_items)

Diese Alternative macht nur die verschiedenen Fälle klar. Obwohl es etwas ausführlich und nicht sehr pythonisch ist (kein Generator, keine vorlagenbasierte Zeichenfolgenformatierung), konzentriert es sich auf Robustheit .

Um der Körperstruktur eine lange Struktur zu geben und verschiedene Teile für die Lesbarkeit zu trennen, habe ich leere Linien (vertikaler Abstand) eingefügt - individuelle Stilpräferenz.

Alle Edge-Cases werden am Anfang abgefangen, um schnell zurückzukehren / fehlzuschlagen (veraltete Schleife vermeiden). Dies ist eine bewährte Methode für die Validierung.

Der Hauptzweck kann leicht aus der letzten Zeile (der Rückgabezeile) abgelesen werden : Drucken von verbundenen Elementen. Die seitlichen Annehmlichkeiten wie fallbasierte Verbindungszeichenfolgen werden buchstäblich als Belag bezeichnet . Die Verfeinerung kann in späteren Iterationen ( Erweiterbarkeit ) eingeführt werden, abhängig von Ihrer Erfahrung, z.

  • verbesserte Formatierung / Druck (mithilfe der praktischen Funktionen von Python)
  • Rückgabe eines Strings (macht die Funktion zu einem Formatierer, unabhängig von der Ausgabeschnittstelle)
  • Junction-Strings parametrisieren (zur Anpassung / Lokalisierung statt fest codiert)

Benutzerfreundlichkeit: Grammatik für die Verwendung von Kommas andin Listen

Ich habe mich vorher über das Komma gewundert andund recherchiert. Das Phänomen, das als serielles Komma oder Oxford-Komma bezeichnet wird , wird im Grammatik-Blog- Beitrag Komma vor und beschrieben . Es heißt im Wesentlichen:

  • Normalerweise setzen Sie ein Komma vor und wenn zwei unabhängige Klauseln verbunden werden.
  • Es ist fast immer optional, ein Komma vor und in eine Liste zu setzen.
  • Sie sollten vorher kein Komma verwenden und wenn Sie nur zwei Eigenschaften erwähnen.

Da ich davon ausgehe, dass die Funktion reine Elemente (Namen, Substantive, Verben) - keine Klauseln - auflisten sollte, habe ich ein einfaches and(ohne serielles Komma ) implementiert, um auch 2 Elemente grammatikalisch korrekt zu behandeln.

Solange die verschiedenen Junctions noch nicht parametrisiert werden können, sollten Sie (implizit) die angewendeten Junction-Regeln in einem Kommentar (doc-string) klären.