Dzisiejsza zagadka brzmi co wypisze ten prosty kod ?
Zachęcam do zabawy razem ze mną. Czytamy zadanie, wypisujemy naszą odpowiedź na kartce i dopiero potem sprawdzamy jak jest naprawdę. Powodzenia !!!
def zrob_liste_osob(uczestnicy, prowadzacy = ['adam', 'rafal']): prowadzacy.extend(uczestnicy) return prowadzacy uczestnicy_python = ['Piotrek', 'Przemek', 'Pankracy'] uczestnicy_c = ['Cezary', 'Cyprian', 'Czesław'] pelna_lista_python = zrob_liste_osob(uczestnicy_python) print(pelna_lista_python) pelna_lista_c = zrob_liste_osob(uczestnicy_c) print(pelna_lista_c)
Nie wiem czy taka odpowiedź Cię zaskoczyła, ale mnie na pewno. Zanim przejdziemy do wyjaśniana problemu druga zagadka. Może naprowadzi Cię na źródło naszych przygód.
def zrob_liste_osob(uczestnicy, prowadzacy = ['adam', 'rafal']): prowadzacy.extend(uczestnicy) return prowadzacy uczestnicy_python = ['Piotrek', 'Przemek', 'Pankracy'] uczestnicy_c = ['Cezary', 'Cyprian', 'Czesław'] pelna_lista_python = zrob_liste_osob(uczestnicy_python) pelna_lista_c = zrob_liste_osob(uczestnicy_c) print(pelna_lista_python) print(pelna_lista_c)
Jak myślisz co wyświetli się tym razem ?
Jeśli dalej nie wiesz co tu się dzieje spokojnie zaraz wszytko będzie jasne.
Co powinien robić nasz kod ?
Nasza funkcja nie robi nic poza rozszerzaniem listy. Jako parametr przyjmuje dwie listy. Rozszerza jedną kosztem drugiej, a następnie zwraca tą już rozszerzoną listę. Celem jest dostanie listy zawierającej wszystkie osoby na kursie, czyli uczestników plus prowadzących. Z uwagi, że prowadzący są zawsze Ci sami 🙂 Nasza funkcja przyjmuje listę [’adam’, rafal] jako parametr domyślny. Chodziło o to by za każdym razem nie podawać tej samej wartości.
Gdzie jest problem?
Geneza naszych nieoczekiwanych problemów tkwi właśnie w wartości domyślnej naszej funkcji. Zauważ, że jeśli podamy do funkcji oba parametry (czyli nie użyjemy parametru domyślnego) problem nie występuje:
def zrob_liste_osob(uczestnicy, prowadzacy = ['adam', 'rafal']): prowadzacy.extend(uczestnicy) return prowadzacy uczestnicy_python = ['Piotrek', 'Przemek', 'Pankracy'] uczestnicy_c = ['Cezary', 'Cyprian', 'Czesław'] pelna_lista_python = zrob_liste_osob(uczestnicy_python, ['adam', 'rafal']) print(pelna_lista_python) pelna_lista_c = zrob_liste_osob(uczestnicy_c, ['adam', 'rafal']) print(pelna_lista_c)
Output:
['adam', 'rafal', 'Piotrek', 'Przemek', 'Pankracy'] ['adam', 'rafal', 'Cezary', 'Cyprian', 'Czesław']
Jak widać wszytko działa poprawnie. Zatem problem jest z naszym parametrem domyślnym.
Czemu to nie działa ?
Parametry domyślne dla funkcji obliczane są w momencie ładowania modułu. Zatem nasza lista tworzona jest tylko raz. Jeśli wywołamy funkcję „zrob_liste_osob” tylko raz to wygląda, że wszytko działa jak należy. Dlatego właśnie błędy tego typu są dość ciężkie do znalezienia. Każde kolejne wywołanie używa tej samej listy. Wszystkie wywołania naszej funkcji współdzielą tą samą listę. Oczywiście zakładając, że funkcja wywoływana jest tylko z jednym parametrem, a drugi pozostaje domyślny.
Podsumowanie
Unikaj używania wartości modyfikowalnych jako parametry domyślne funkcji. Domyślna lista, mapa, czy też funkcja ” datetime.datetime.now()” to złe pomysły. Mogą spowodować błędy, które mogą być trudne do znalezienia, albo co gorsza pojawią się dopiero po jakimś czasie używania aplikacji.