Effektives Python-Hinweiselement 20 Verwenden Sie None und die Dokumentationszeichenfolge, wenn Sie dynamische Standardargumente angeben

Es ist ein Memo, das das Buch Python von O'Reilly Japan schreibt. https://www.oreilly.co.jp/books/9784873117560/ P47~50

Seien Sie vorsichtig, wenn Sie dynamische Argumente in Funktionsargumente einfügen

Zum Beispiel, wenn Sie eine Funktion definieren, die gleichzeitig die Anmeldezeit und die Protokollierungsnachricht ausgibt

from datetime import datetime
from time import sleep

def log(massage, when=datetime.now()):
    print('%s: %s' % (when, massage))

Wenn Sie der Funktion log () eine Nachricht als Argument geben, wird diese Zeit gleichzeitig mit der Nachricht ausgegeben ... Wenn ich es tatsächlich versuche

log('Hi there!')
sleep(1)
log('Hi there!')

>>>
2016-06-14 00:22:04.668549: Hi there!
2016-06-14 00:22:04.668549: Hi there!

Die Zeit ist dieselbe, obwohl ich 1s lang sleep () gesetzt habe. Darüber hinaus ist diese Zeit nicht die Zeit, zu der die Nachricht eingegeben wird, sondern die Zeit, zu der die Funktion log () definiert ist. Warum passiert das?

Das Standardargument wird beim Aufruf des Moduls nur einmal ausgewertet

Das heißt, datetime.now () wird nur für den Moment ausgewertet, in dem das Funktionsprotokoll () definiert ist, und alle Werte danach sind gleich. ** Um dies zu beheben, setzen Sie das Standardargument auf Keine **

def log2(massage, when=None):
    """Lof a massage with a timestamp.
    
    Args:
        massage: Massage to print.
        when: datetime of when the massage occurred.
            Dafaults to the present time.
    """
    when = datetime.now() if when is None else when
    print('%s: %s' % (when, massage))

Das Attribut None wird dem Argument im Voraus gegeben und wann wird jedes Mal in der Funktion definiert und aufgerufen. Zu diesem Zeitpunkt ist es leicht zu verstehen, ob Sie das Verhalten in das Dokument schreiben

log2('Hi there!')
sleep(1)
log2('Hi there!')

>>>
2016-06-14 00:34:21.793073: Hi there!
2016-06-14 00:34:22.794493: Hi there!

Der Zeitstempel ist jetzt korrekt.

Ein anderes Beispiel! Für Funktionen, die JSON-Daten laden

def decode(data, default={}):
    try:
        return json.loads(data)
    except ValueError:
        return default

Immer wenn ich versuche, die decodierten Daten mit der Funktion decode () als JSON-Daten aufzurufen

foo = decode('bad data')
foo ['sruff'] = 5
bar = decode('also bad')
bar['meep'] = 1
print('Foo:', foo)
print('Bar:', bar)

>>>
Foo: {'sruff': 5, 'meep': 1}
Bar: {'sruff': 5, 'meep': 1}

In diesem Fall wird davon ausgegangen, dass Foo und Bar jeweils ein Wörterbuch mit einem Schlüssel und einem Wert sind. Wie bei den obigen dynamischen Argumenten wird das Standardwörterbuch jedoch festgelegt, wenn decode () definiert wird. Selbst wenn Sie decode () mehrmals aufrufen, erbt das darin enthaltene Wörterbuch daher immer eines.

Dies wird auch gelöst, indem None in die Standardeinstellung gesetzt wird (Verhalten wird in das Dokument geschrieben).

def decode2(data, default=None):
    """Load JSON data from a string.
    Args:
        data: JSON data to decode
        default: Value to return if decoding fails.
            Dafaults to an empty dictionary.
    """
    if default is None:
        default = {}
    try:
        return json.loads(data)
    except ValueError:
        return default

foo = decode2('bad data')
foo ['sruff'] = 5
bar = decode2('also bad')
bar['meep'] = 1
print('Foo:', foo)
print('Bar:', bar)

>>>
Foo: {'sruff': 5}
Bar: {'meep': 1}

** Zusammenfassung ** --Funktionsvorgaben werden nur einmal gelesen --Dynamisches Argument ist Keine

Recommended Posts

Effektives Python-Hinweiselement 20 Verwenden Sie None und die Dokumentationszeichenfolge, wenn Sie dynamische Standardargumente angeben
Effektiver Python-Hinweis Punkt 17 Respektieren Sie die Sicherheit, wenn Sie Iteratoren für Argumente verwenden
Effektives Python-Memo-Element 18 Verwenden Sie Positionsargumente variabler Länge, um das Erscheinungsbild sauberer zu gestalten
Seien Sie vorsichtig, wenn Sie den Standardargumentwert in der Python 3-Serie angeben
Effektives Python-Memo Element 7 Verwenden Sie die Listeneinschlussnotation anstelle von Karte und Filter
[Python] Verwenden Sie und und oder beim Erstellen von Variablen
Verwenden Sie Python auf Raspberry Pi 3, um die LED zu beleuchten, wenn es dunkel wird!
Wann wirken sich Python-Funktionen auf die Argumente des Aufrufers aus?
Angeben des Bereichs von Ruby- und Python-Arrays
Python Hinweis: Wenn Sie einer Zeichenfolge einen Wert zuweisen
json.dumping Keine in Python gibt die Zeichenfolge null zurück
Der Zeitpunkt, zu dem der Wert des Standardarguments ausgewertet wird, unterscheidet sich zwischen Ruby und Python.
Wann werden die Standardargumente in Python gebunden? Wenn die Variable im Abschluss gebunden ist, wird die Auswertung verschoben.