Czasami wydaje się naturalne, że domyślny parametr jest pustą listą. Jednak w takich sytuacjach Python zachowuje się w nieoczekiwany sposób .
Jeśli na przykład mam funkcję:
def my_func(working_list = []):
working_list.append("a")
print(working_list)
Pierwsze wywołanie ustawienia domyślnego zadziała, ale późniejsze wywołania zaktualizują istniejącą listę (z jednym „a” na każde połączenie) i wydrukują zaktualizowaną wersję.
Jaki jest więc pythonowy sposób uzyskania pożądanego zachowania (nowa lista przy każdym połączeniu)?
python
python-3.x
John Mulder
źródło
źródło
Odpowiedzi:
Dokumentacja mówi, że powinieneś używać go
None
jako domyślnego i jawnie testować go w treści funkcji.źródło
f()
listę, musisz wywołać,f(*l)
która jest obrzydliwa. Gorzej, wdrożeniemate(['larch', 'finch', 'robin'], ['bumble', 'honey', 'queen'])
byłoby SUCK z varargs. O wiele lepiej, jeśli tak jestdef mate(birds=[], bees=[]):
.Istniejące odpowiedzi dostarczyły już bezpośrednich rozwiązań, o które proszono. Jednakże, ponieważ jest to bardzo częsta pułapka dla nowych programistów Pythona, warto dodać wyjaśnienie, dlaczego python zachowuje się w ten sposób, co jest ładnie podsumowane w " The Hitchhikers Guide to Python " jako " Mutable Default Arguments ": http: // docs .python-guide.org / pl / latest / writing / gotchas /
Cytuj: „ Domyślne argumenty Pythona są oceniane raz, gdy funkcja jest zdefiniowana, a nie za każdym razem, gdy funkcja jest wywoływana (tak jak to jest w przypadku Rubiego). Oznacza to, że jeśli użyjesz zmiennego argumentu domyślnego i zmienisz go, będziesz zmutował ten obiekt również dla wszystkich przyszłych wywołań funkcji "
Przykładowy kod do implementacji:
źródło
Nie ma to znaczenia w tym przypadku, ale możesz użyć tożsamości obiektu, aby przetestować brak:
Możesz również skorzystać z tego, jak operator boolowski lub jest zdefiniowany w Pythonie:
Chociaż będzie to zachowywać się nieoczekiwanie, jeśli wywołujący poda pustą listę (która liczy się jako fałsz) jako working_list i oczekuje, że funkcja zmodyfikuje podaną przez niego listę.
źródło
Jeśli celem funkcji jest zmodyfikowanie parametru przekazanego jako
working_list
, zobacz odpowiedź HenryR (= None, sprawdź brak wewnątrz).Ale jeśli nie zamierzałeś modyfikować argumentu, po prostu użyj go jako punktu wyjścia dla listy, możesz go po prostu skopiować:
(lub w tym prostym przypadku tylko,
print starting_list + ["a"]
ale myślę, że to był tylko przykład zabawki)Ogólnie rzecz biorąc, mutowanie argumentów to zły styl w Pythonie. Jedynymi funkcjami, od których w pełni oczekuje się, że będą mutować obiekt, są metody obiektu. Jeszcze rzadziej mutuje się opcjonalny argument - czy efekt uboczny, który występuje tylko w niektórych wywołaniach, jest naprawdę najlepszym interfejsem?
Jeśli robisz to z nawyku „argumentów wyjściowych” w języku C, jest to całkowicie niepotrzebne - zawsze możesz zwrócić wiele wartości jako krotkę.
Jeśli robisz to, aby efektywnie budować długą listę wyników bez tworzenia list pośrednich, rozważ napisanie jej jako generatora i używanie go
result_list.extend(myFunc())
podczas wywoływania. W ten sposób konwencje powołania pozostają bardzo czyste.Jednym ze wzorców, w którym często przeprowadza się mutację opcjonalnego argumentu, jest ukryty argument typu „memo” w funkcjach rekurencyjnych:
źródło
Mogę być poza tematem, ale pamiętaj, że jeśli chcesz przekazać tylko zmienną liczbę argumentów, pythonowym sposobem jest przekazanie krotki
*args
lub słownika**kargs
. Są one opcjonalne i lepsze niż składniamyFunc([1, 2, 3])
.Jeśli chcesz przekazać krotkę:
Jeśli chcesz przekazać słownik:
źródło
Udzielono już dobrych i poprawnych odpowiedzi. Chciałem tylko podać inną składnię do pisania tego, co chcesz zrobić, co uważam za piękniejsze, gdy na przykład chcesz utworzyć klasę z domyślnymi pustymi listami:
Ten fragment wykorzystuje składnię operatora if else. Podoba mi się to zwłaszcza dlatego, że jest to zgrabny, mały, jednolinijkowy tekst bez dwukropków itp. I prawie brzmi jak normalne angielskie zdanie. :)
W twoim przypadku mógłbyś pisać
źródło
Wziąłem klasę rozszerzenia UCSC
Python for programmer
Co jest prawdą w przypadku: def Fn (data = []):
Odpowiedź:
źródło