Was ist der pythonic Weg Standardparameter zu vermeiden, die leeren Listen sind?

StackOverflow https://stackoverflow.com/questions/366422

  •  21-08-2019
  •  | 
  •  

Frage

Manchmal scheint es natürlich, einen Standardparameter zu haben, das eine leere Liste ist. Doch Python gibt ein unerwartetes Verhalten in diesen Situationen .

Wenn Sie zum Beispiel, ich habe eine Funktion:

def my_func(working_list = []):
    working_list.append("a")
    print(working_list)

Das erste Mal ist es der Standard genannt wird funktionieren wird, fordert jedoch nach, dass die bestehende Liste (mit einer „a“ jeder Anruf) und drucken Sie die aktualisierte Version aktualisiert.

Also, was ist die pythonic Art und Weise das Verhalten Ich wünsche (eine frische Liste bei jedem Aufruf)?

zu bekommen
War es hilfreich?

Lösung

def my_func(working_list=None):
    if working_list is None: 
        working_list = []

    working_list.append("a")
    print(working_list)

docs sagen Sie als Standard verwenden None sollte und ausdrücklich Test für ihn im Körper der Funktion.

Andere Tipps

Vorhandene Antworten haben bereits die direkte Fertige Lösungen wie gefragt. Da dies jedoch ist ein sehr häufiger Fehler für neue Python-Programmierer, es lohnt sich, die Erklärung hinzuzufügen, warum Python auf diese Weise verhält, die schön in „ die Tramper-Führer zu Python “ zusammengefasst als „ Veränderliche Standardargumente ": http://docs.python-guide.org/en/latest/writing/ gotchas /

Zitat:. „ Pythons Standardargumente einmal ausgewertet werden, wenn die Funktion definiert ist, nicht jedes Mal der Funktion aufgerufen wird (wie es in etwa Ruby ist) Dies bedeutet, dass, wenn Sie ein veränderbares Standardargument verwenden und mutiert es werden Sie und haben für alle zukünftigen Anrufe an die Funktion als auch das Objekt mutiert "

Beispielcode zu implementieren es:

def foo(element, to=None):
    if to is None:
        to = []
    to.append(element)
    return to

Nicht, dass es wichtig ist in diesem Fall, aber Sie können Objektidentität testen für Keine Verwendung:

if working_list is None: working_list = []

Sie können auch die Vorteile wie die Booleschen Operator nehmen oder in Python definiert:

working_list = working_list or []

Obwohl dies unerwartet verhalten wird, wenn der Anrufer eine leere Liste gibt (die als falsch zählt) als working_list und erwartet, dass Ihre Funktion die Liste er es gab zu ändern.

Wenn die Absicht der Funktion ist auf modify den Parameter als working_list vergangen, siehe HenryR Antwort (= None, überprüft Keine innen).

Aber wenn Sie nicht die Absicht, das Argument zu mutieren, verwenden Sie es nur als Punkt für eine Liste beginnen, können Sie einfach kopieren:

def myFunc(starting_list = []):
    starting_list = list(starting_list)
    starting_list.append("a")
    print starting_list

(oder in diesem einfachen Fall nur print starting_list + ["a"] aber ich denke, das war nur ein Spielzeug Beispiel)

In der Regel Ihre Argumente zu mutieren, ist schlechter Stil in Python. Die einzigen Funktionen, die in vollem Umfang zu erwarten sind, ein Objekt zu mutieren sind Methoden des Objekts. Es ist noch seltener ein optionales Argument zu mutieren - ist eine Nebenwirkung, die nur in einigen Anrufen wirklich die beste Schnittstelle geschieht

  • Wenn Sie es aus der C-Gewohnheit „Ausgabeargumente“ zu tun, das ist völlig unnötig -. Sie immer mehrere Werte als Tupel zurückgeben

  • Wenn Sie dies tun, effizient eine lange Liste von Ergebnissen zu bauen, ohne Zwischenlisten zu erstellen, betrachtet es als Generator zu schreiben und mit result_list.extend(myFunc()), wenn Sie es fordern. Auf diese Weise Ihre Aufrufkonventionen bleibt sehr sauber.

Ein Muster, bei dem einer optionalen arg mutiert ist häufig getan ist ein verstecktes "Memo" arg in rekursiven Funktionen:

def depth_first_walk_graph(graph, node, _visited=None):
    if _visited is None:
        _visited = set()  # create memo once in top-level call

    if node in _visited:
        return
    _visited.add(node)
    for neighbour in graph[node]:
        depth_first_walk_graph(graph, neighbour, _visited)

Ich könnte off-topic, aber denken Sie daran, dass, wenn Sie nur eine variable Anzahl von Argumenten übergeben wollen, die pythonic Weise ein Tupel *args oder ein Wörterbuch **kargs passieren soll. Diese sind optional und sind besser als die Syntax myFunc([1, 2, 3]).

Wenn Sie ein Tupel weitergeben müssen:

def myFunc(arg1, *args):
  print args
  w = []
  w += args
  print w
>>>myFunc(1, 2, 3, 4, 5, 6, 7)
(2, 3, 4, 5, 6, 7)
[2, 3, 4, 5, 6, 7]

Wenn Sie ein Wörterbuch zu übergeben:

def myFunc(arg1, **kargs):
   print kargs
>>>myFunc(1, option1=2, option2=3)
{'option2' : 2, 'option1' : 3}

Es gibt bereits gut gewesen und die richtigen Antworten zur Verfügung gestellt. Ich wollte nur eine andere Syntax geben, zu schreiben, was Sie tun möchten, die ich schöner finden, wenn Sie zum Beispiel eine Klasse mit Standard leeren Listen erstellen möchten:

class Node(object):
    def __init__(self, _id, val, parents=None, children=None):
        self.id = _id
        self.val = val
        self.parents = parents if parents is not None else []
        self.children = children if children is not None else []

Dieser Code-Schnipsel nutzt die, wenn sonst Operator Syntax. Ich mag es, vor allem, weil es ein netter kleiner Einzeiler ohne Doppelpunkte ist usw. beteiligt und es liest fast wie ein normaler englischen Satz. :)

In Ihrem Fall könnten Sie schreiben

def myFunc(working_list=None):
    working_list = [] if working_list is None else working_list
    working_list.append("a")
    print working_list

Ich habe die UCSC Erweiterungsklasse Python for programmer

Welche wahr ist aus: def Fn (data = []):

  

a) ist eine gute Idee, so dass Ihre Datenlisten bei jedem Aufruf leer starten.

     

b) ist eine gute Idee, so dass alle Anrufe auf die Funktion, die nicht liefern keine Argumente auf den Anruf die leere Liste als Daten.

     

c) ist eine vernünftige Idee, solange Ihre Daten ist eine Liste von Strings.

     

d) ist eine schlechte Idee, weil der Standard [] wird die Daten ansammeln und der Standard [] wird mit folgenden Aufrufen ändern.

Antwort:

  

d) ist eine schlechte Idee, weil der Standard [] wird die Daten ansammeln und der Standard [] wird mit folgenden Aufrufen ändern.

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