2016-06-28 13 views
0

Ich schrieb 2 einfache Codes in Python, die das gleiche funktionieren sollte, aber es tut nicht. Wenn Sie mir sagen können, warum ist das, und erklären Sie mir auch mehr über die "alles ist ein Objekt in Python". Dank :)Warum gibt es Unterschiede zwischen diesen beiden Codes?

def f(p=[]): 
    print p 
    f.a += 1 
    print id(p) 
    if(f.a == 1): 
     p = p + [4] 
    else: 
     p = p + [5] 
    return p 
f.a = 0 
f() 
f() 
f() 

Antwort:

[] 
40564496 
[] 
40564496 
[] 
40564496 
def f(p=[]): 
    print p 
    f.a += 1 
    print id(p) 
    if(f.a == 1): 
     p += [4] 
    else: 
     p +=[5] 
    return p 
#print f() 
#print f() 
f.a = 0 
f() 
f() 
f() 

Antwort:

[] 
40892176 
[4] 
40892176 
[4, 5] 
40892176 

wie Sie sehen - der erste Code jedes Mal eine neue Liste, und die zweite zu der zuletzt verwendeten ...

Antwort

1

Sie sollten nie ein veränderbares Objekt als Standardwert in Python-Funktion als dort übergeben wird nur ein sein. Folglich verwendet Ihre zweite Funktion immer dieselbe Liste, die bei der Erstellung der Funktion instantiiert wurde. Der erste erzeugt dagegen neue Listen während p = p + [4] Zuordnungen, daher gibt es keine Mutation des Standardarg. dieser Code auf diese Weise:

def f(p=None): 
    if p is None: 
     p = [] 

    print p 
    f.a += 1 
    print id(p) 
    if(f.a == 1): 
     p += [4] 
    else: 
     p +=[5] 
    return p 

* von nie meine ich „wenn Sie wirklich wissen, was Sie tun“. Es gibt immer eine Ausnahme von der Regel, aber wenn Sie eine Mutable als Standardwert übergeben müssen, müssen Sie ihre Konsequenzen sehr gut verstehen, daher würden Sie diese Antwort wahrscheinlich sowieso nicht lesen. Insbesondere ist es in vielen Python Styleguides entmutigt, wie Google python style guide

nicht veränderbare Objekte als Standardwerte in der Funktion oder Methode Definition verwenden.

Dies auch Pylint Warnung W0102

gefährlich-default-Wert (W0102) führen sollte: Gefährliche Standardwert% s als Argument verwendet, wenn ein veränderliches Wert als Liste oder Wörterbuch erfasst wird, in ein Standardwert für ein Argument.

+0

Es ist nicht so, dass Sie veränderbare Objekte als Standardwerte ** niemals ** weitergeben sollten, sondern Sie sollten verstehen, was es bedeutet. –

+0

@juanpa - sicher, es gibt immer eine Ausnahme (siehe aktualisierte Antwort). – lejlot

+0

Ich würde nicht sagen, "* vererbe niemals [a] veränderbare Objekte als Standardwerte." Es gibt bestimmte Fälle, in denen ein solches Verhalten erwünscht und nützlich ist (d. H. Einen Memoisierungsdekorator schreiben). – pzp

1

Die Operatoren obj += other und obj = obj + other sind nicht identisch. Das vorherige verwendet oft Inplace Modifikation, während das später in der Regel ein neues Objekt erstellt. Bei Listen ist obj += other dasselbe wie obj.extend(other).

Die zweite wichtige Sache ist, dass def Anweisungen nur einmal pro Bereich ausgewertet werden. Wenn Sie eine Funktion im Modulbereich definieren, wird def einmal ausgewertet - dies beinhaltet die Erstellung der Standardparameter!

def foo(bar=[]): 
    print(id(bar)) 

In diesem Fall Leiste wird standardmäßig immer auf die gleiche Liste Objekt, das erstellt wurde, wenn def foo zuerst ausgewertet wurde. Wenn Sie den Standardwert ändern, wird der Standardwert übernommen. Kontrast dies mit:

def foo(bar=None): 
    bar = bar if bar is not None else [] 
    print(id(bar)) 

In diesem Fall ist die Standardliste ist neu jedes Mal die Funktion aufgerufen wird.

Verwandte Themen