Мне очень помогли мои предыдущие вопросы по обнаружению лап и пальцев внутри лапы , но все эти решения работают только для одного измерения за раз.
Теперь у меня есть данные, которые состоят из:
- около 30 собак;
- каждое имеет 24 измерения (разделенных на несколько подгрупп);
- каждое измерение имеет как минимум 4 контакта (по одному на каждую лапу) и
- каждый контакт делится на 5 частей и
- имеет несколько параметров, таких как время контакта, местоположение, общая сила и т. д.
Очевидно, что склеивание всего в один большой объект не приведет к его разрезанию, поэтому я решил, что мне нужно использовать классы вместо текущего множества функций. Но хотя я прочитал главу Learning Python о классах, я не смог применить ее к своему собственному коду ( ссылка на GitHub )
Я также чувствую, что довольно странно обрабатывать все данные каждый раз, когда я хочу получить какую-то информацию. Как только я узнаю расположение каждой лапы, у меня нет оснований снова рассчитывать это. Кроме того, я хочу сравнить все лапы одной и той же собаки, чтобы определить, какой контакт принадлежит какой лапе (передняя / задняя, левая / правая). Это станет беспорядком, если я продолжу использовать только функции.
Так что теперь я ищу совет о том, как создавать классы, которые позволят мне обрабатывать мои данные ( ссылки на сжатые данные одной собаки ) разумным способом.
источник
Ответы:
Как спроектировать класс.
Записать слова. Вы начали это делать. Некоторые люди не знают и удивляются, почему у них проблемы.
Разложите ваш набор слов в простые утверждения о том, что будут делать эти объекты. То есть запишите различные вычисления, которые вы будете делать для этих вещей. Ваш короткий список из 30 собак, 24 измерений, 4 контактов и нескольких «параметров» на контакт интересен, но это только часть истории. Ваши «местоположения каждой лапы» и «сравнить все лапы одной и той же собаки, чтобы определить, какой контакт принадлежит какой лапе», являются следующим шагом в проектировании объекта.
Подчеркните существительные. Шутки в сторону. Некоторые люди обсуждают ценность этого, но я считаю, что для начинающих разработчиков ОО это помогает. Подчеркните существительные.
Просмотрите существительные. Общие существительные, такие как «параметр» и «измерение», должны быть заменены конкретными, конкретными существительными, которые относятся к вашей проблеме в вашей проблемной области. Особенности помогут прояснить проблему. Обобщения просто элитные детали.
Для каждого существительного («контакт», «лапа», «собака» и т. Д.) Запишите атрибуты этого существительного и действия, в которых участвует этот объект. Не сокращайте это. Каждый атрибут. Например, «Набор данных содержит 30 собак».
Для каждого атрибута определите, является ли это отношением к определенному существительному, или к какому-либо другому виду «примитивных» или «атомарных» данных, таких как строка или число с плавающей запятой, или к чему-то неприводимому.
Для каждого действия или операции вы должны определить, какое существительное несет ответственность, а какие просто участвуют. Это вопрос "изменчивости". Некоторые объекты обновляются, другие нет. Изменяемые объекты должны нести полную ответственность за свои мутации.
На этом этапе вы можете начать преобразовывать существительные в определения классов. Некоторые коллективные существительные являются списками, словарями, кортежами, наборами или именованными кортежами, и вам не нужно много работать. Другие классы являются более сложными, либо из-за сложных производных данных, либо из-за выполняемого обновления / мутации.
Не забудьте протестировать каждый класс изолированно с помощью unittest.
Кроме того, нет закона, согласно которому классы должны быть изменяемыми. В вашем случае, например, у вас почти нет изменяемых данных. То, что у вас есть, это производные данные, созданные функциями преобразования из исходного набора данных.
источник
Следующие советы (аналогичные советам @ S.Lott) взяты из книги « Начинающий Python: от новичка до профессионала».
Чтобы уточнить класс, книга также советует, что мы можем сделать следующее:
источник
Мне нравится подход TDD ... Итак, начните с написания тестов того, каким должно быть поведение. И написать код, который проходит. На данный момент, не беспокойтесь о дизайне, просто получите набор тестов и программное обеспечение, которое проходит. Не беспокойтесь, если у вас будет один большой уродливый класс со сложными методами.
Иногда, во время этого начального процесса, вы обнаружите поведение, которое сложно протестировать и которое необходимо разложить только для проверки. Это может быть намеком на то, что отдельный класс гарантирован.
Тогда самое интересное ... рефакторинг. После того, как у вас есть работающее программное обеспечение, вы можете увидеть сложные части. Часто появляются небольшие карманы поведения, предлагающие новый класс, но если нет, просто ищите способы упростить код. Извлечение сервисных объектов и объектов стоимости. Упростите ваши методы.
Если вы используете git правильно (вы используете git, не так ли?), Вы можете очень быстро поэкспериментировать с каким-то конкретным разложением во время рефакторинга, а затем отказаться от него и вернуться обратно, если это не упрощает вещи.
Написав сначала проверенный рабочий код, вы должны получить глубокое понимание проблемной области, которую вы не могли бы легко получить с помощью подхода, ориентированного на первый дизайн. Написание тестов и кода подталкивает вас к тому параличу «с чего начать».
источник
Вся идея дизайна ОО состоит в том, чтобы сделать вашу карту кода соответствующей вашей проблеме, поэтому, когда, например, вы хотите сделать первый шаг собаки, вы делаете что-то вроде:
Теперь может оказаться, что для вашего случая вам нужно прочитать файл необработанных данных и вычислить расположение шагов. Все это может быть скрыто в функции footstep (), чтобы это происходило только один раз. Что-то вроде:
[Теперь это своего рода шаблон кэширования. В первый раз, когда он идет и читает данные шага, в следующий раз он просто получает их из self._footsteps.]
Но да, получить правильный дизайн ОО может быть сложно. Подумайте больше о том, что вы хотите сделать со своими данными, и это сообщит, какие методы вам нужно применить к каким классам.
источник
Написание ваших существительных, глаголов, прилагательных - это отличный подход, но я предпочитаю думать о дизайне классов как о том, что нужно задать вопрос, какие данные должны быть скрыты ?
Представьте, что у вас есть
Query
объект иDatabase
объект:Query
Объект поможет создать и сохранить запрос - магазин, ключ здесь, как функция может помочь вам создать так же легко. Может быть, вы могли бы остатьсяQuery().select('Country').from_table('User').where('Country == "Brazil"')
. Не имеет значения, какой именно синтаксис - это ваша работа! - ключ в том, что объект помогает вам что-то скрыть , в данном случае это данные, необходимые для хранения и вывода запроса. Сила объекта заключается в синтаксисе его использования (в данном случае некоторого умного связывания) и необходимости знать, что он хранит, чтобы заставить его работать. Если все сделано правильно,Query
объект может выводить запросы для более чем одной базы данных. Он внутренне будет хранить определенный формат, но при выводе может легко конвертировать в другие форматы (Postgres, MySQL, MongoDB).Теперь давайте подумаем об
Database
объекте. Что это скрывает и хранит? Совершенно очевидно, что он не может хранить все содержимое базы данных, потому что именно поэтому у нас есть база данных! Так в чем же смысл? Цель состоит в том, чтобы скрыть, как работает база данных от людей, которые используютDatabase
объект. Хорошие классы упростят рассуждения при манипулировании внутренним состоянием. Для этогоDatabase
объекта вы можете скрыть, как работают сетевые вызовы, или выполнять пакетные запросы или обновления, или обеспечить уровень кэширования.Проблема в том
Database
объект ОГРОМНЫЙ. Он представляет, как получить доступ к базе данных, поэтому под прикрытием он может делать все что угодно. Очевидно, что с сетью, кэшированием и пакетированием довольно сложно справиться в зависимости от вашей системы, поэтому было бы очень полезно скрыть их. Но, как заметят многие, база данных безумно сложна, и чем дальше вы получаете необработанные вызовы БД, тем сложнее настроить производительность и понять, как все работает.Это фундаментальный компромисс ООП. Если вы выберете правильную абстракцию, это упростит кодирование (String, Array, Dictionary), если вы выберете слишком большую абстракцию (Database, EmailManager, NetworkingManager), она может стать слишком сложной, чтобы действительно понять, как она работает, или что ожидать. Цель состоит в том, чтобы скрыть сложность , но некоторая сложность необходима. Хорошее эмпирическое правило заключается в том, чтобы начать избегать
Manager
объектов и вместо этого создавать классы, которые похожиstructs
- все, что они делают, это хранят данные, с некоторыми вспомогательными методами для создания / манипулирования данными, чтобы сделать вашу жизнь проще. Например, в случаеEmailManager
запуска с вызываемой функцией,sendEmail
которая принимаетEmail
объект. Это простая отправная точка, и код очень прост для понимания.Что касается вашего примера, подумайте, какие данные должны быть вместе, чтобы рассчитать то, что вы ищете. Например, если вы хотите узнать, как далеко зашло животное, у вас могут быть
AnimalStep
иAnimalTrip
(коллекция AnimalSteps) классы. Теперь, когда каждая Поездка имеет все данные шага, она должна иметь возможность разобраться с этим, возможно,AnimalTrip.calculateDistance()
имеет смысл.источник
После просмотра вашего связанного кода мне кажется, что вам лучше не создавать класс Dog в данный момент. Скорее, вы должны использовать панды и датафреймы . Фрейм данных - это таблица со столбцами. Вы dataframe бы столбцы , такие как:
dog_id
,contact_part
,contact_time
,contact_location
и т.д. Панда использует Numpy массивы за кулисами, и имеет множество удобных методов для вас:my_measurements['dog_id']=='Charly'
my_measurements.save('filename.pickle')
pandas.read_csv()
вместо чтения текстовых файлов вручную.источник