Saya sudah mendapatkan bantuan yang sangat luar biasa pada pertanyaan saya sebelumnya untuk mendeteksi kaki dan kaki dalam satu kaki , tetapi semua solusi ini hanya bekerja untuk satu pengukuran pada satu waktu.
Sekarang saya memiliki data yang terdiri dari:
- sekitar 30 anjing;
- masing-masing memiliki 24 pengukuran (dibagi menjadi beberapa subkelompok);
- setiap pengukuran memiliki setidaknya 4 kontak (satu untuk setiap kaki) dan
- setiap kontak dibagi menjadi 5 bagian dan
- memiliki beberapa parameter, seperti waktu kontak, lokasi, kekuatan total dll.
Jelas menempel semuanya menjadi satu objek besar tidak akan memotongnya, jadi saya pikir saya perlu menggunakan kelas bukan fungsi membunuh saat ini. Tetapi meskipun saya sudah membaca bab Belajar Python tentang kelas, saya gagal menerapkannya pada kode saya sendiri ( tautan GitHub )
Saya juga merasa agak aneh untuk memproses semua data setiap kali saya ingin mendapatkan beberapa informasi. Setelah saya tahu lokasi masing-masing kaki, tidak ada alasan bagi saya untuk menghitung ini lagi. Selanjutnya, saya ingin membandingkan semua cakar anjing yang sama untuk menentukan kontak mana yang memiliki cakar (depan / belakang, kiri / kanan). Ini akan menjadi berantakan jika saya terus menggunakan fungsi saja.
Jadi sekarang saya mencari saran tentang cara membuat kelas yang memungkinkan saya memproses data saya ( tautan ke data zip dari satu anjing ) dengan cara yang masuk akal.
sumber
Jawaban:
Bagaimana cara mendesain sebuah kelas.
Tuliskan kata-katanya. Anda mulai melakukan ini. Beberapa orang tidak dan heran mengapa mereka memiliki masalah.
Rentangkan serangkaian kata Anda menjadi pernyataan sederhana tentang apa yang akan dilakukan objek-objek ini. Artinya, tuliskan berbagai perhitungan yang akan Anda lakukan pada hal-hal ini. Daftar pendek 30 anjing, 24 pengukuran, 4 kontak, dan beberapa "parameter" per kontak menarik, tetapi hanya sebagian dari cerita. "Lokasi masing-masing kaki" dan "bandingkan semua kaki anjing yang sama untuk menentukan kontak mana yang memiliki kaki" adalah langkah selanjutnya dalam desain objek.
Garis bawahi kata benda. Serius. Beberapa orang memperdebatkan nilai ini, tetapi saya menemukan bahwa untuk pengembang OO pertama kali itu membantu. Garis bawahi kata benda.
Tinjau kata benda. Kata benda umum seperti "parameter" dan "pengukuran" perlu diganti dengan kata benda konkret tertentu yang berlaku untuk masalah Anda di domain masalah Anda. Spesifik membantu mengklarifikasi masalah. Obat generik hanya menghilangkan detail.
Untuk setiap kata benda ("kontak", "paw", "dog", dll.) Tuliskan atribut dari kata benda itu dan tindakan yang dilakukan objek tersebut. Jangan pintas ini. Setiap atribut. "Kumpulan Data berisi 30 Anjing" misalnya penting.
Untuk setiap atribut, identifikasi apakah ini merupakan hubungan dengan kata benda yang ditentukan, atau jenis lain dari data "primitif" atau "atom" seperti string atau float atau sesuatu yang tidak dapat direduksi.
Untuk setiap tindakan atau operasi, Anda harus mengidentifikasi kata benda mana yang memiliki tanggung jawab, dan kata benda mana yang hanya berpartisipasi. Ini adalah pertanyaan tentang "mutabilitas". Beberapa objek diperbarui, yang lain tidak. Benda yang bisa berubah harus memiliki tanggung jawab total atas mutasinya.
Pada titik ini, Anda dapat mulai mengubah kata benda menjadi definisi kelas. Beberapa kata benda kolektif adalah daftar, kamus, tuple, set, atau namesuple, dan Anda tidak perlu melakukan terlalu banyak pekerjaan. Kelas-kelas lain lebih kompleks, baik karena data turunan kompleks atau karena beberapa pembaruan / mutasi yang dilakukan.
Jangan lupa untuk menguji setiap kelas secara terpisah menggunakan unittest.
Juga, tidak ada hukum yang mengatakan bahwa kelas harus bisa berubah. Dalam kasus Anda, misalnya, Anda hampir tidak memiliki data yang dapat diubah. Apa yang Anda miliki adalah data turunan, dibuat oleh fungsi transformasi dari dataset sumber.
sumber
Nasihat berikut (mirip dengan nasihat S.Lott) berasal dari buku, Beginning Python: From Novice to Professional
Untuk memperbaiki kelas, buku ini juga menyarankan agar kita dapat melakukan hal berikut:
sumber
Saya suka pendekatan TDD ... Jadi mulailah dengan menulis tes untuk apa perilaku yang Anda inginkan. Dan tulis kode yang lewat. Pada titik ini, jangan terlalu khawatir tentang desain, cukup dapatkan test suite dan perangkat lunak yang lulus. Jangan khawatir jika Anda berakhir dengan satu kelas jelek besar, dengan metode kompleks.
Terkadang, selama proses awal ini, Anda akan menemukan perilaku yang sulit untuk diuji dan perlu diurai, hanya untuk diuji. Ini mungkin merupakan petunjuk bahwa kelas yang terpisah dijamin.
Kemudian bagian yang menyenangkan ... refactoring. Setelah Anda memiliki perangkat lunak yang berfungsi, Anda dapat melihat bagian yang rumit. Seringkali kantong kecil perilaku akan menjadi jelas, menyarankan kelas baru, tetapi jika tidak, cari saja cara untuk menyederhanakan kode. Ekstrak objek layanan dan nilai objek. Sederhanakan metode Anda.
Jika Anda menggunakan git dengan benar (Anda menggunakan git, bukan?), Anda dapat dengan cepat bereksperimen dengan beberapa dekomposisi selama refactoring, dan kemudian meninggalkannya dan kembali lagi jika itu tidak menyederhanakan banyak hal.
Dengan menulis kode kerja yang teruji terlebih dahulu, Anda harus mendapatkan wawasan yang mendalam tentang domain masalah yang tidak mudah Anda dapatkan dengan pendekatan desain-pertama. Tes tertulis dan kode mendorong Anda melewati kelumpuhan "di mana saya mulai".
sumber
Seluruh ide desain OO adalah membuat peta kode untuk masalah Anda, jadi ketika, misalnya, Anda ingin langkah pertama seekor anjing, Anda melakukan sesuatu seperti:
Sekarang, mungkin untuk kasus Anda, Anda perlu membaca di file data mentah Anda dan menghitung lokasi jejak. Semua ini bisa disembunyikan dalam fungsi footstep () sehingga hanya terjadi sekali. Sesuatu seperti:
[Ini sekarang semacam pola caching. Pertama kali ia pergi dan membaca data footstep, kali berikutnya ia hanya mendapatkannya dari self._footsteps.]
Tapi ya, mendapatkan desain OO yang benar bisa sulit. Pikirkan lebih lanjut tentang hal-hal yang ingin Anda lakukan untuk data Anda, dan itu akan menginformasikan metode apa yang perlu Anda terapkan ke kelas apa.
sumber
Menuliskan kata benda, kata kerja, kata sifat Anda merupakan pendekatan yang hebat, tetapi saya lebih suka menganggap desain kelas sebagai mengajukan pertanyaan data apa yang harus disembunyikan ?
Bayangkan Anda memiliki
Query
objek danDatabase
objek:The
Query
objek akan membantu Anda membuat dan menyimpan query - toko, adalah kunci di sini, sebagai fungsi bisa membantu Anda membuat satu dengan mudah. Mungkin Anda bisa tinggal:Query().select('Country').from_table('User').where('Country == "Brazil"')
. Tidak masalah persis sintaksisnya - itu adalah pekerjaan Anda! - kuncinya adalah objek membantu Anda menyembunyikan sesuatu , dalam hal ini data yang diperlukan untuk menyimpan dan menampilkan kueri. Kekuatan objek berasal dari sintaks menggunakannya (dalam hal ini beberapa rantai pintar) dan tidak perlu tahu apa yang disimpannya untuk membuatnya bekerja. Jika dilakukan dengan benar,Query
objek dapat menampilkan kueri untuk lebih dari satu basis data. Secara internal ia akan menyimpan format tertentu tetapi dapat dengan mudah dikonversi ke format lain saat mengeluarkan (Postgres, MySQL, MongoDB).Sekarang mari kita pikirkan
Database
objeknya. Apa yang disembunyikan dan disimpan oleh ini? Yah jelas itu tidak bisa menyimpan isi penuh dari database, karena itu sebabnya kami punya database! Jadi apa gunanya? Tujuannya adalah untuk menyembunyikan cara kerja database dari orang yang menggunakanDatabase
objek. Kelas yang baik akan menyederhanakan penalaran ketika memanipulasi keadaan internal. UntukDatabase
objek ini Anda bisa menyembunyikan cara kerja panggilan jaringan, atau permintaan batch atau pembaruan, atau memberikan lapisan caching.Masalahnya adalah
Database
objek ini BESAR. Ini mewakili cara mengakses database, jadi di balik selimut itu bisa melakukan apa saja. Jelas jaringan, caching, dan batching sangat sulit untuk ditangani tergantung pada sistem Anda, jadi menyembunyikannya akan sangat membantu. Tetapi, seperti yang diketahui oleh banyak orang, sebuah basis data sangat kompleks, dan semakin jauh dari panggilan DB mentah yang Anda dapatkan, semakin sulit untuk menyesuaikan kinerja dan memahami cara kerja berbagai hal.Ini adalah tradeoff mendasar dari OOP. Jika Anda memilih abstraksi yang benar, membuat pengodean menjadi lebih mudah (String, Array, Dictionary), jika Anda memilih abstraksi yang terlalu besar (Database, EmailManager, NetworkingManager), mungkin menjadi terlalu rumit untuk benar-benar memahami cara kerjanya, atau apa yang harus dilakukan. mengharapkan. Tujuannya adalah untuk menyembunyikan kompleksitas , tetapi beberapa kompleksitas diperlukan. Aturan praktis yang baik adalah mulai menghindari
Manager
objek, dan sebaliknya membuat kelas yang sepertistructs
- yang mereka lakukan hanyalah memegang data, dengan beberapa metode pembantu untuk membuat / memanipulasi data untuk membuat hidup Anda lebih mudah. Misalnya, dalam kasusEmailManager
mulai dengan fungsi yang dipanggilsendEmail
yang mengambilEmail
objek. Ini adalah titik awal yang sederhana dan kodenya sangat mudah dimengerti.Sebagai contoh Anda, pikirkan tentang data apa yang perlu disatukan untuk menghitung apa yang Anda cari. Jika Anda ingin tahu seberapa jauh seekor binatang berjalan, misalnya, Anda dapat memiliki
AnimalStep
danAnimalTrip
(mengumpulkan AnimalSteps) kelas. Sekarang setiap perjalanan memiliki semua data Langkah, maka harus bisa mencari tahu tentang hal itu, mungkinAnimalTrip.calculateDistance()
masuk akal.sumber
Setelah membaca kode tertaut Anda, sepertinya Anda lebih baik tidak merancang kelas Anjing pada saat ini. Sebaliknya, Anda harus menggunakan Panda dan bingkai data . Kerangka data adalah tabel dengan kolom. Anda dataframe akan memiliki kolom seperti:
dog_id
,contact_part
,contact_time
,contact_location
, dll Panda menggunakan Numpy array di belakang layar, dan memiliki banyak metode kenyamanan untuk Anda:my_measurements['dog_id']=='Charly'
my_measurements.save('filename.pickle')
pandas.read_csv()
daripada membaca file teks secara manual.sumber