Jak zaprojektować klasę w Pythonie?

Miałem naprawdę niesamowitą pomoc w moich poprzednich pytaniach do wykrywania łapy i palce w łapie , ale wszystkie te rozwiązania działają tylko dla jednego pomiaru na raz.

Teraz mam DANE , które składają się z:

  • około 30 psów;
  • każdy ma 24 pomiary (podzielone na kilka podgrup);
  • każdy pomiar ma co najmniej 4 styki (po jednym na każdą łapę) i
    • każdy kontakt jest podzielony na 5 części i
    • ma kilka parametrów, takich jak czas kontaktu, lokalizacja, Siła całkowita itp.

alt text

Oczywiście przyklejenie wszystkiego do jednego dużego obiektu nie spowoduje jego przecięcia, więc uznałem, że muszę używać klas zamiast obecnych funkcji. Ale mimo, że przeczytałem rozdział Nauka Pythona o klasach, nie mogę zastosować go do własnego kodu (GitHub link )

Czuję też, że to dość dziwne przetwarzać wszystkie dane za każdym razem chcę uzyskać jakieś informacje. Kiedy poznam położenie każdej łapy, Nie będę musiał tego ponownie obliczać. Ponadto chcę porównać wszystkie łapy tego samego psa, aby określić, który Kontakt należy do której łapy (przód/tył, lewa/prawa). Stanie się to bałaganem, jeśli będę nadal używać tylko funkcji.

Więc teraz szukam rady, jak stworzyć klasy, które pozwolą mi przetwarzać moje dane (link do zipped danych jednego psa) w rozsądna Moda.

Author: Community, 2010-11-17

6 answers

Jak zaprojektować klasę.

  1. Zapisz słowa. Zacząłeś to robić. Niektórzy ludzie nie mają i zastanawiają się, dlaczego mają problemy.

  2. Rozwiń swój zestaw słów na proste stwierdzenia o tym, co te obiekty będą robić. To znaczy, Zapisz różne obliczenia, które będziesz robił na tych rzeczach. Twoja krótka lista 30 psów, 24 pomiary, 4 kontakty i kilka "parametrów" na kontakt jest interesująca, ale tylko część historii. Twój "lokalizacje każdej łapy" i "porównaj wszystkie łapy tego samego psa, aby określić, który Kontakt należy do której łapy" to kolejny krok w projektowaniu obiektu.

  3. Podkreśl rzeczowniki. Poważnie. Niektórzy dyskutują o wartości tego, ale uważam, że dla programistów oo po raz pierwszy pomaga. Podkreśl rzeczowniki.

  4. Przejrzyj rzeczowniki. Rzeczowniki rodzajowe takie jak" parameter "i" measurement " należy zastąpić konkretnymi, konkretnymi rzeczownikami, które odnoszą się do twojego problemu w Twoim problem domeny. Szczegóły pomagają wyjaśnić problem. Generyki po prostu pomijają szczegóły.

  5. Dla każdego rzeczownika ("kontakt", "łapa", "pies" itp.) Zapisz atrybuty tego rzeczownika i działania, w które ten obiekt się angażuje. Nie skracaj tego. Każdy atrybut. "Zestaw danych zawiera 30 psów" na przykład jest ważny.

  6. Dla każdego atrybutu określ, czy jest to związek z określonym rzeczownikiem, czy innym rodzajem" prymitywnych "lub" atomowych " danych, takich jak ciąg znaków lub / align = "left" /

  7. Dla każdej czynności lub operacji musisz określić, który rzeczownik jest odpowiedzialny, a który rzeczownik tylko uczestniczy. To kwestia "zmienności". Niektóre obiekty są aktualizowane, inne nie. Mutowalne obiekty muszą ponosić całkowitą odpowiedzialność za swoje mutacje.

  8. W tym momencie możesz zacząć przekształcać rzeczowniki w definicje klas. Niektóre rzeczowniki zbiorowe są listami, słownikami, krotkami, zestawami lub nazwami, a Ty nie trzeba robić zbyt wiele pracy. Inne klasy są bardziej złożone, albo z powodu złożonych danych pochodnych, albo z powodu jakiejś aktualizacji/mutacji, która jest wykonywana.

Nie zapomnij przetestować każdej klasy w izolacji za pomocą unittest.

Nie ma również prawa, które mówi, że klasy muszą być mutowalne. W Twoim przypadku, na przykład, nie masz prawie żadnych mutowalnych danych. To, co masz, to dane pochodne, tworzone przez funkcje transformacji z zestawu danych źródłowych.

 428
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-17 11:21:51

Poniższe Rady (podobne do rad @S. Lott) pochodzą z książki, Beginning Python: From Novice to Professional

  1. Napisz opis swojego problemu (co powinien zrobić problem?). Podkreśl wszystkie rzeczowniki, czasowniki i przymiotniki.

  2. Przejrzyj rzeczowniki, szukając potencjalnych klas.

  3. Przejrzyj czasowniki, szukając potencjalnych metod.

  4. Przejść przez przymiotniki, szukając potencjału atrybuty

  5. Przydziel metody i atrybuty do klas

Aby udoskonalić klasę, książka radzi również, abyśmy mogli wykonać następujące czynności:

  1. Zapisz (lub wymyśl) zestaw przypadków użycia - - - scenariuszy, w jaki sposób twój program może być używany. Spróbuj pokryć wszystkie funkcjonalnie.

  2. Przemyśl krok po kroku każdy przypadek użycia, upewniając się, że wszystko, czego potrzebujemy, jest pokryte.

 22
Author: mitchelllc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-22 18:18:57

Podoba mi się podejście TDD... Zacznij więc od pisania testów, jakie chcesz, aby zachowanie było. I napisz kod, który przejdzie. W tym momencie nie martw się zbytnio o projekt, po prostu zdobądź pakiet testowy i oprogramowanie, które przejdzie. Nie martw się, jeśli skończysz z jedną wielką brzydką klasą, ze złożonymi metodami.

Czasami, podczas tego początkowego procesu, można znaleźć zachowanie, które jest trudne do przetestowania i wymaga rozkładu, tylko dla testowalności. Może to być wskazówka, że oddzielna klasa jest / align = "left" /

Potem zabawa... refaktoryzacja. Po zainstalowaniu działającego oprogramowania możesz zobaczyć złożone elementy. Często małe kieszenie zachowań staną się widoczne, sugerując nową klasę, ale jeśli nie, po prostu poszukaj sposobów na uproszczenie kodu. Wyodrębnij obiekty usługowe i Obiekty wartości. Uprość swoje metody.

Jeśli używasz git poprawnie (używasz git, prawda?), można bardzo szybko eksperymentować z jakimś konkretnym rozkładem podczas refaktoryzacji, a następnie zrezygnować to i wrócić z powrotem, jeśli to nie uprości rzeczy.

Pisząc testowany kod roboczy najpierw powinieneś uzyskać intymny wgląd w problemową dziedzinę, której nie możesz łatwo uzyskać dzięki podejściu design-first. Pisanie testów i kodu popycha cię do paraliżu "od czego zacząć".

 13
Author: Les Nightingill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-22 18:42:31

Cała idea OO design polega na tym, aby Twój kod mapował się do twojego problemu, więc gdy np. chcesz pierwszy krok psa, robisz coś w stylu:

dog.footstep(0)

Teraz może być tak, że w Twoim przypadku musisz przeczytać w pliku surowych danych i obliczyć lokalizacje kroków. Wszystko to może być ukryte w funkcji footstep() tak, że dzieje się to tylko raz. Coś w stylu:

 class Dog:
   def __init__(self):
     self._footsteps=None 
   def footstep(self,n):
     if not self._footsteps:
        self.readInFootsteps(...)
     return self._footsteps[n]

[jest to teraz rodzaj wzorca buforowania. Pierwszy raz idzie i odczytuje dane kroków, kolejne czasy po prostu dostaje to od siebie._footsteps.]

Ale tak, poprawienie projektu oo może być trudne. Pomyśl więcej o tym, co chcesz zrobić ze swoimi danymi, a to poinformuje, jakie metody musisz zastosować do jakich klas.
 3
Author: Spacedman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-17 10:07:20

Pisanie rzeczowników, czasowników, przymiotników jest świetnym podejściem, ale wolę myśleć o projektowaniu klas jako zadaniu pytania jakie dane powinny być ukryte ?

Imagine you had a Query object and a Database object:

Obiekt Query pomoże Ci utworzyć i zapisać zapytanie -- store, jest tutaj kluczem, ponieważ funkcja może pomóc Ci utworzyć takie samo łatwo. Może mógłbyś zostać: Query().select('Country').from_table('User').where('Country == "Brazil"'). Nie ma znaczenia składnia-to Twoja praca! -- kluczem jest obiekt pomaga ukryć coś , w tym przypadku dane niezbędne do przechowywania i wypisywania zapytania. Moc obiektu wynika ze składni używania go (w tym przypadku sprytnego chaining) i nie konieczności wiedzieć, co przechowuje, aby działał. Jeśli zrobi się to poprawnie, obiekt Query może wysyłać zapytania do więcej niż jednej bazy danych. Wewnętrznie przechowywałby określony format, ale mógłby łatwo konwertować do innych formatów podczas wysyłania (Postgres, MySQL, MongoDB).

A teraz Przemyśl obiekt Database. Co to ukrywa i przechowuje? Cóż, najwyraźniej nie może przechowywać pełnej zawartości bazy danych, ponieważ dlatego mamy bazę danych! Więc jaki to ma sens? Celem jest ukrycie działania bazy danych przed osobami używającymi obiektu Database. Dobre klasy uproszczą rozumowanie podczas manipulowania stanem wewnętrznym. Dla tego obiektu Database można ukryć sposób działania połączeń sieciowych, zapytań wsadowych lub aktualizacji, lub dostarczyć warstwę buforowania.

The problem w tym, że obiekt Database jest ogromny. Reprezentuje sposób dostępu do bazy danych, więc pod przykrywką może zrobić wszystko i wszystko. Oczywiście sieci, buforowanie i grupowanie są dość trudne do opanowania w zależności od systemu, więc ukrywanie ich byłoby bardzo pomocne. Ale, jak wiele osób zauważy, baza danych jest szalenie złożona, a im dalej od surowych wywołań DB otrzymujesz, tym trudniej jest dostroić się do wydajności i zrozumieć, jak to działa.

To jest fundamentalne wymiana OOP. Jeśli wybierzesz odpowiednią abstrakcję, kodowanie będzie prostsze (ciąg znaków, tablica, Słownik), jeśli wybierzesz zbyt dużą abstrakcję (baza danych, EmailManager, NetworkingManager), może stać się zbyt skomplikowane, aby naprawdę zrozumieć, jak to działa lub czego się spodziewać. Celem jest ukrycie złożoności , ale pewna złożoność jest konieczna. Dobrą zasadą jest, aby zacząć od unikania Manager obiektów, a zamiast tego tworzyć klasy, które są jak structs - wszystko, co robią, to przechowują dane, z niektórymi metody pomocnicze do tworzenia / manipulowania danymi, aby ułatwić sobie życie. Na przykład, w przypadku EmailManager zacznij od funkcji o nazwie sendEmail, która zajmuje obiekt Email. Jest to prosty punkt wyjścia, a kod jest bardzo łatwy do zrozumienia.

Jeśli chodzi o twój przykład, zastanów się, jakie dane muszą być razem, aby obliczyć, czego szukasz. Jeśli chcesz wiedzieć, jak daleko zwierzę idzie, na przykład, możesz mieć klasy AnimalStep i AnimalTrip (kolekcja AnimalSteps). Teraz, gdy każda podróż ma wszystkie dane o krokach, powinna być w stanie dowiedzieć się o tym, być może {16]} ma sens.

 2
Author: Evan Moran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-23 01:08:58

Po sprawdzeniu twojego linkowanego kodu, wydaje mi się, że lepiej Ci będzie , a nie w tym momencie projektować klasę psów. Zamiast tego należy używać pand i dataframes . Ramka danych jest tabelą z kolumnami. Macie takie kolumny jak: dog_id, contact_part, contact_time, contact_location, itd. Pandy używa tablic Numpy za kulisami i ma wiele wygodnych metod dla Ciebie: {]}

  • wybierz psa np.: my_measurements['dog_id']=='Charly'
  • Zapisz dane: my_measurements.save('filename.pickle')
  • rozważ użycie pandas.read_csv() zamiast ręcznego czytania plików tekstowych.
 2
Author: cyborg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-24 00:24:38