Benar, kebanyakan bahasa pemrograman menjadikan urutan parameter sebagai bagian dari kontrak pemanggilan fungsi, tetapi ini tidak harus demikian. Mengapa demikian? Pemahaman saya tentang pertanyaan ini adalah, jika Python berbeda dengan bahasa pemrograman lain dalam hal ini. Selain jawaban bagus lainnya untuk Python 2, harap pertimbangkan yang berikut:
__named_only_start = object()
def info(param1,param2,param3,_p=__named_only_start,spacing=10,collapse=1):
if _p is not __named_only_start:
raise TypeError("info() takes at most 3 positional arguments")
return str(param1+param2+param3) +"-"+ str(spacing) +"-"+ str(collapse)
Satu-satunya cara pemanggil dapat memberikan argumen spacing
dan secara collapse
posisional (tanpa pengecualian) adalah:
info(arg1, arg2, arg3, module.__named_only_start, 11, 2)
Konvensi untuk tidak menggunakan elemen privat milik modul lain sudah sangat mendasar di Python. Seperti pada Python itu sendiri, konvensi untuk parameter ini hanya akan diterapkan secara semi-diterapkan.
Jika tidak, panggilan harus dalam bentuk:
info(arg1, arg2, arg3, spacing=11, collapse=2)
Sebuah panggilan
info(arg1, arg2, arg3, 11, 2)
akan menetapkan nilai 11 ke parameter _p
dan pengecualian yang muncul dengan instruksi pertama fungsi.
Karakteristik:
- Parameter sebelum
_p=__named_only_start
diterima secara posisional (atau dengan nama).
- Parameter setelah
_p=__named_only_start
harus diberikan hanya dengan nama (kecuali jika pengetahuan tentang objek sentinel khusus __named_only_start
diperoleh dan digunakan).
Kelebihan:
- Parameternya eksplisit dalam jumlah dan artinya (nanti jika nama baik juga dipilih, tentunya).
- Jika sentinel ditentukan sebagai parameter pertama, maka semua argumen harus ditentukan dengan nama.
- Saat memanggil fungsi, dimungkinkan untuk beralih ke mode posisi dengan menggunakan objek sentinel
__named_only_start
di posisi yang sesuai.
- Sebuah kinerja yang lebih baik dari alternatif lain dapat diantisipasi.
Kekurangan:
Pemeriksaan terjadi selama waktu proses, bukan waktu kompilasi.
- Penggunaan parameter tambahan (meskipun bukan argumen) dan pemeriksaan tambahan. Penurunan kinerja kecil sehubungan dengan fungsi reguler.
- Fungsionalitas adalah hack tanpa dukungan langsung oleh bahasa (lihat catatan di bawah).
- Saat memanggil fungsi, dimungkinkan untuk beralih ke mode posisi dengan menggunakan objek sentinel
__named_only_start
di posisi yang benar. Ya, ini juga bisa dilihat sebagai seorang profesional.
Harap diingat bahwa jawaban ini hanya berlaku untuk Python 2. Python 3 menerapkan mekanisme yang didukung bahasa yang serupa, tetapi sangat elegan, yang dijelaskan dalam jawaban lain.
Saya telah menemukan bahwa ketika saya membuka pikiran dan memikirkannya, tidak ada pertanyaan atau keputusan orang lain yang tampak bodoh, bodoh, atau konyol. Justru sebaliknya: Saya biasanya belajar banyak.
_named_only_start
, menjadi tidak mungkin untuk merujuknya dari modul eksternal, yang mengeluarkan pro dan kontra. (garis bawah utama tunggal pada cakupan modul bersifat pribadi, IIRC)__named_only_start
dan anamed_only_start
(tanpa garis bawah awal), yang kedua untuk menunjukkan bahwa mode bernama "direkomendasikan", tetapi tidak untuk tingkat "dipromosikan secara aktif" (karena salah satunya bersifat publik dan lainnya tidak). Mengenai "privasi" yang_names
dimulai dengan garis bawah, hal itu tidak terlalu ditegakkan oleh bahasa: hal ini dapat dengan mudah dielakkan dengan penggunaan impor (non- *) tertentu atau nama yang memenuhi syarat. Inilah sebabnya mengapa beberapa dokumen Python lebih suka menggunakan istilah "non-publik" daripada "pribadi".Anda dapat melakukannya dengan cara yang bekerja pada Python 2 dan Python 3 , dengan membuat argumen kata kunci pertama yang "palsu" dengan nilai default yang tidak akan muncul "secara alami". Argumen kata kunci tersebut dapat diawali dengan satu atau beberapa argumen tanpa nilai:
Ini akan memungkinkan:
tapi tidak:
Jika Anda mengubah fungsinya menjadi:
maka semua argumen harus memiliki kata kunci dan
info(odbchelper)
tidak akan berfungsi lagi.Ini akan memungkinkan Anda untuk menempatkan argumen kata kunci tambahan di sembarang tempat
_kw
, tanpa memaksa Anda untuk meletakkannya setelah entri terakhir. Ini sering kali masuk akal, misalnya mengelompokkan sesuatu secara logis atau menyusun kata kunci menurut abjad dapat membantu pemeliharaan dan pengembangan.Jadi tidak perlu kembali menggunakan
def(**kwargs)
dan kehilangan informasi tanda tangan di editor pintar Anda. Kontrak sosial Anda adalah memberikan informasi tertentu, dengan memaksa (beberapa di antaranya) meminta kata kunci, urutan penyajiannya, menjadi tidak relevan.sumber
Memperbarui:
Saya menyadari bahwa menggunakan
**kwargs
tidak akan menyelesaikan masalah. Jika programmer Anda mengubah argumen fungsi sesuai keinginan, seseorang dapat, misalnya, mengubah fungsinya menjadi ini:dan kode lama akan rusak lagi (karena sekarang setiap pemanggilan fungsi harus menyertakan argumen pertama).
Itu benar-benar tergantung pada apa yang dikatakan Bryan.
Secara umum, saat mengubah fungsi, argumen baru harus selalu berakhir. Jika tidak, itu akan merusak kode. Harus jelas.
Jika seseorang mengubah fungsi sehingga kode rusak, perubahan ini harus ditolak.
(Seperti yang dikatakan Bryan, ini seperti kontrak)
Dengan melihat tanda tangan dari fungsi (yaitu
def info(object, spacing=10, collapse=1)
), seseorang harus segera melihat bahwa setiap argumen yang tidak memiliki nilai default, adalah wajib.Untuk apa argumennya, harus masuk ke docstring.
Jawaban lama (disimpan untuk kelengkapan) :
Ini mungkin bukan solusi yang baik:Anda dapat mendefinisikan fungsi dengan cara ini:
kwargs
adalah kamus yang berisi argumen kata kunci. Anda dapat memeriksa apakah ada argumen wajib dan jika tidak, buat pengecualian.Sisi negatifnya adalah, itu mungkin tidak terlalu jelas lagi, argumen mana yang mungkin, tetapi dengan docstring yang tepat, itu akan baik-baik saja.
sumber
Argumen hanya kata kunci python3 (
*
) dapat disimulasikan di python2.x dengan**kwargs
Perhatikan kode python3 berikut:
dan perilakunya:
Ini dapat disimulasikan dengan menggunakan yang berikut, perhatikan bahwa saya telah mengambil kebebasan untuk beralih
TypeError
keKeyError
dalam kasus "argumen bernama yang diperlukan", tidak akan terlalu sulit untuk membuat jenis pengecualian yang sama itu jugaDan perilaku:
Resepnya bekerja dengan baik di python3.x, tetapi harus dihindari jika Anda hanya python3.x
sumber
kwargs.pop('foo')
apakah idiom Python 2? Saya perlu memperbarui gaya pengkodean saya. Saya masih menggunakan pendekatan ini di Python 3 🤔Anda dapat mendeklarasikan fungsi Anda sebagai
**args
hanya menerima . Itu akan mengamanatkan argumen kata kunci tetapi Anda memiliki beberapa pekerjaan tambahan untuk memastikan hanya nama yang valid yang diteruskan.sumber
foo(**kwargs)
. Apa yang saya lolos ke itu?foo(killme=True, when="rightnowplease")
dict
.Seperti jawaban lain mengatakan, mengubah tanda tangan fungsi adalah ide yang buruk. Tambahkan parameter baru di akhir, atau perbaiki setiap pemanggil jika argumen dimasukkan.
Jika Anda masih ingin melakukannya, gunakan fungsi dekorator dan fungsi inspect.getargspec . Ini akan digunakan seperti ini:
Implementasi
require_named_args
dibiarkan sebagai latihan bagi pembaca.Saya tidak akan mengganggu. Ini akan menjadi lambat setiap kali fungsi dipanggil, dan Anda akan mendapatkan hasil yang lebih baik dengan menulis kode dengan lebih hati-hati.
sumber
Anda bisa menggunakan
**
operator:dengan cara ini orang-orang dipaksa untuk menggunakan parameter bernama.
sumber
di python jika menggunakan * args itu berarti Anda dapat mengirimkan n-jumlah argumen untuk parameter ini - yang akan menjadi daftar di dalam fungsi untuk mengakses
dan jika menggunakan ** kw itu berarti argumen kata kuncinya, yang dapat diakses sebagai dict - Anda dapat memberikan n-number dari kw args, dan jika Anda ingin membatasi pengguna tersebut harus memasukkan urutan dan argumen secara berurutan maka jangan gunakan * dan ** - (cara pythonic untuk memberikan solusi umum untuk arsitektur besar ...)
jika Anda ingin membatasi fungsi Anda dengan nilai default maka Anda dapat memeriksa di dalamnya
sumber
Saya tidak mengerti mengapa seorang programmer akan menambahkan parameter di antara dua lainnya di tempat pertama.
Jika Anda ingin parameter fungsi digunakan dengan nama (mis.
info(spacing=15, object=odbchelper)
) Maka tidak masalah dalam urutan apa parameter tersebut didefinisikan, jadi sebaiknya Anda meletakkan parameter baru di bagian akhir.Jika Anda benar-benar ingin urutan penting maka tidak dapat mengharapkan apa pun untuk bekerja jika Anda mengubahnya!
sumber