Membaca Pengantar Praktis untuk Pemrograman Fungsional Mary Rose Cook , ia memberikan contoh anti-pola
def format_bands(bands):
for band in bands:
band['country'] = 'Canada'
band['name'] = band['name'].replace('.', '')
band['name'] = band['name'].title()
sejak
- fungsi melakukan lebih dari satu hal
- namanya tidak deskriptif
- ini memiliki efek samping
Sebagai solusi yang diusulkan, ia menyarankan fungsi anonim pipelining
pipeline_each(bands, [call(lambda x: 'Canada', 'country'),
call(lambda x: x.replace('.', ''), 'name'),
call(str.title, 'name')])
Namun bagi saya ini tampaknya memiliki kelemahan yang bahkan lebih tidak dapat diuji; setidaknya format_bands dapat memiliki unit test untuk memeriksa apakah ia melakukan apa yang dimaksudkan, tetapi bagaimana cara menguji pipa? Atau apakah gagasan bahwa fungsi anonim begitu jelas sehingga tidak perlu diuji?
Aplikasi dunia nyata saya untuk ini adalah mencoba membuat pandas
kode saya lebih fungsional. Saya akan sering memiliki semacam pipa di dalam fungsi "munging"
def munge_data(df)
df['name'] = df['name'].str.lower()
df = df.drop_duplicates()
return df
Atau menulis ulang dengan gaya pipeline:
def munge_data(df)
munged = (df.assign(lambda x: x['name'].str.lower()
.drop_duplicates())
return munged
Adakah saran untuk praktik terbaik dalam situasi seperti ini?
python
unit-testing
Max Flander
sumber
sumber
Jawaban:
Saya pikir Anda melewatkan mungkin bagian yang lebih penting dari contoh buku yang diperbaiki. Perubahan yang lebih mendasar pada kode adalah dari metode yang beroperasi pada semua nilai dalam daftar menjadi operasi pada satu elemen.
Sudah ada fungsi seperti
iter
(dalam hal ini bernamapipeline_foreach
) yang melakukan operasi yang diberikan pada semua elemen dalam daftar. Tidak perlu menduplikasi denganfor
loop. Juga menggunakan operasi daftar terkenal membuat niat Anda jelas. Denganmap
Anda mentransformasikan nilai. Denganiter
Anda melakukan efek samping dengan setiap elemen. Denganfor
loop kamu ... yah, kamu tidak benar-benar tahu sampai kamu melihatnya.Contoh kode yang dikoreksi masih sangat tidak fungsional, karena (sejauh yang saya tahu) mengubah nilai dalam daftar tanpa mengembalikannya, mencegah perpipaan atau komposisi fungsi lebih lanjut. Metode yang disukai secara fungsional
map
akan membuat daftar band baru dengan pembaruancountry
danname
. Kemudian Anda bisa menyalurkan output itu ke fungsi berikutnya atau menulismap
dengan fungsi lain yang mengambil daftar band. Denganiter
, itu seperti jalan buntu pipa.Saya pikir kode hasil akhir memiliki fungsi kecil yang terlalu sepele untuk mengganggu pengujian di sini. Lagi pula, Anda tidak perlu menulis unit test melawan
replace
atautitle
. Sekarang mungkin Anda ingin menyusun ini menjadi fungsi dan unit tes Anda sendiri bahwa kombinasi yang diinginkan tercapai pada satu item. Saya sendiri, saya mungkin akan berubahformat_bands
menjadiformat_band
tunggal, menjatuhkan for loop, dan meneleponpipeline_each(bands, format_band)
. Kemudian Anda dapat menguji format_band untuk memastikan Anda tidak melupakan sesuatu.Bagaimanapun, ke kode Anda. Contoh kode kedua Anda tampaknya lebih banyak pipeline-y. Tetapi itu saja tidak memberikan manfaat pemrograman fungsional. Dalam praktiknya, pemrograman fungsional berarti memastikan kompatibilitas fungsi dengan fungsi lain dengan mendefinisikan kompatibilitasnya hanya dalam hal input dan outputnya. Jika ada efek samping tersembunyi di dalam fungsi, maka terlepas dari input / output yang sejalan dengan fungsi lainnya, Anda tidak dapat mengetahui apakah mereka kompatibel hingga waktu berjalan. Namun, jika dua fungsi bebas efek samping dan cocok dengan input-ke-input maka Anda dapat menyalurkan atau menyusunnya dengan sedikit khawatir akan hasil yang tidak terduga.
sumber