Terkadang wajar jika memiliki parameter default yang berupa daftar kosong. Namun Python memberikan perilaku yang tidak terduga dalam situasi ini .
Jika misalnya, saya punya fungsi:
def my_func(working_list = []):
working_list.append("a")
print(working_list)
Pertama kali disebut default akan berfungsi, tetapi panggilan setelah itu akan memperbarui daftar yang ada (dengan satu "a" untuk setiap panggilan) dan mencetak versi yang diperbarui.
Jadi, apa cara pythonic untuk mendapatkan perilaku yang saya inginkan (daftar baru di setiap panggilan)?
python
python-3.x
John Mulder
sumber
sumber
Jawaban:
Dokumen tersebut mengatakan Anda harus menggunakan
None
sebagai default dan secara eksplisit mengujinya di badan fungsi.sumber
f()
daftar, Anda harus memanggilf(*l)
mana yang kotor. Lebih buruk lagi, implementasimate(['larch', 'finch', 'robin'], ['bumble', 'honey', 'queen'])
akan SUCK w / varargs. Jauh lebih baik jika itudef mate(birds=[], bees=[]):
.Jawaban yang ada telah memberikan solusi langsung seperti yang diminta. Namun, karena ini adalah perangkap yang sangat umum untuk programmer Python baru, ada baiknya menambahkan penjelasan mengapa python berperilaku seperti ini, yang dirangkum dengan baik dalam " Panduan Penumpang untuk Python " sebagai " Argumen Default yang Dapat Diubah ": http: // docs .python-guide.org / id / latest / writing / gotchas /
Kutipan: " Argumen default Python dievaluasi satu kali ketika fungsi didefinisikan, tidak setiap kali fungsi dipanggil (seperti yang di katakan, Ruby). Ini berarti bahwa jika Anda menggunakan argumen default yang bisa berubah dan memutasinya, Anda akan dan memiliki mutasi objek itu untuk semua panggilan mendatang ke fungsi juga "
Kode contoh untuk menerapkannya:
sumber
Tidak penting dalam kasus ini, tetapi Anda dapat menggunakan identitas objek untuk menguji None:
Anda juga dapat memanfaatkan cara operator boolean atau didefinisikan dengan python:
Meskipun ini akan berperilaku tidak terduga jika pemanggil memberi Anda daftar kosong (yang dihitung sebagai false) sebagai working_list dan mengharapkan fungsi Anda untuk mengubah daftar yang dia berikan.
sumber
Jika maksud dari fungsi ini adalah untuk mengubah parameter yang diteruskan sebagai
working_list
, lihat jawaban HenryR (= Tidak ada, periksa Tidak ada di dalam).Tetapi jika Anda tidak bermaksud untuk mengubah argumen, gunakan saja sebagai titik awal untuk daftar, Anda cukup menyalinnya:
(atau dalam kasus sederhana ini,
print starting_list + ["a"]
tapi saya rasa itu hanya contoh mainan)Secara umum, mutasi argumen Anda adalah gaya yang buruk di Python. Satu-satunya fungsi yang sepenuhnya diharapkan untuk mengubah suatu objek adalah metode objek tersebut. Bahkan lebih jarang untuk mengubah argumen opsional - apakah efek samping yang terjadi hanya dalam beberapa panggilan benar-benar merupakan antarmuka terbaik?
Jika Anda melakukannya dari kebiasaan C "argumen keluaran", itu sama sekali tidak perlu - Anda selalu dapat mengembalikan beberapa nilai sebagai tupel.
Jika Anda melakukan ini untuk membuat daftar hasil yang panjang secara efisien tanpa membuat daftar perantara, pertimbangkan untuk menulisnya sebagai generator dan menggunakannya
result_list.extend(myFunc())
saat Anda memanggilnya. Dengan cara ini, konvensi panggilan Anda tetap sangat bersih.Salah satu pola di mana bermutasi arg opsional yang sering dilakukan adalah tersembunyi "memo" arg dalam fungsi rekursif:
sumber
Saya mungkin di luar topik, tetapi ingat bahwa jika Anda hanya ingin memberikan sejumlah variabel argumen, cara pythonic adalah dengan mengirimkan tupel
*args
atau kamus**kargs
. Ini opsional dan lebih baik daripada sintaksmyFunc([1, 2, 3])
.Jika Anda ingin melewatkan tupel:
Jika Anda ingin lulus kamus:
sumber
Sudah ada jawaban yang baik dan benar yang diberikan. Saya hanya ingin memberikan sintaks lain untuk menulis apa yang ingin Anda lakukan yang menurut saya lebih indah ketika Anda misalnya ingin membuat kelas dengan daftar kosong default:
Cuplikan ini menggunakan sintaks operator if else. Saya menyukainya terutama karena ini merupakan satu baris kecil yang rapi tanpa titik dua, dll. Terlibat dan hampir terbaca seperti kalimat bahasa Inggris normal. :)
Dalam kasus Anda, Anda bisa menulis
sumber
Saya mengambil kelas ekstensi UCSC
Python for programmer
Yang benar dari: def Fn (data = []):
Menjawab:
sumber