2010-10-15 13 views
17

Niedawno omawiałem problem z kodowaniem, który miałem, a ktoś, kto szukał kodu, powiedział, że lista podklas jest zła (mój problem nie był związany z tą klasą). Powiedział, że nie powinieneś tego robić i że przyszedł z wieloma złymi efektami ubocznymi. Czy to prawda?Co wziąć pod uwagę przed utworzeniem podklasy?

Pytam, czy lista jest ogólnie zła podklasa, a jeśli tak, jakie są tego powody. Alternatywnie, co powinienem wziąć pod uwagę przed podklasowaniem listy w Pythonie?

+2

Lista podklasy nie jest z gruntu zła, ale jest wiele przypadków, w których naprawdę nie jest to, co chcesz zrobić. Nie możemy odpowiedzieć, czy tak jest w tym przypadku, chyba że podasz nam szczegóły. –

Odpowiedz

17

Nie ma korzyści dla podklasy list. Żadna z metod nie użyje żadnych nadpisanych metod, więc możesz mieć nieoczekiwane błędy. Ponadto często mylące jest robienie takich rzeczy, jak self.append zamiast self.foos.append, a zwłaszcza self[4] zamiast self.foos[4], aby uzyskać dostęp do danych. Możesz zrobić coś, co działa dokładnie tak jak lista lub (lepiej) jakkolwiek bardzo przypomina listę, którą naprawdę chcesz, a zarazem podklasy object.

+3

Co zrobić, jeśli chcemy dodać atrybut do listy? Załóżmy na przykład, że mamy mylist = []. Chcemy czegoś takiego jak mylist.x = 3. – riza

+1

@Selinap, W przypadku, w którym chciałem, aby mój stan zawierał listę czegoś i int, nadal prawdopodobnie użyłbym kompozycji. Używanie dziedziczenia po to powoduje zamieszanie na piśmie, zamieszanie w używaniu i naprawdę nic nie zyskuje. –

+2

To wydaje się nieprawdziwe z python 3. Zawierają one w tym celu ['collections.UserList'] (https://docs.python.org/3.4/library/collections.html#collections.UserList). Sugeruje nawet, że możliwe jest teraz podklasowanie z listy: "Potrzeba tej klasy została częściowo zastąpiona przez zdolność do podklasy bezpośrednio z listy;" (Rozumiem, że jest to stary temat i powyższe komentarze prawdopodobnie były prawdziwe podczas pisania, po prostu chcę to wyjaśnić dla osób, które teraz znajdują to pytanie). – Claude

11

Myślę, że pierwsze pytanie, jakie sobie zadam, brzmi: "Czy mój nowy obiekt to naprawdę lista?". Czy chodzi jak lista, rozmawia jak lista? Czy jest coś innego?

Jeśli jest to lista, wszystkie standardowe metody listy powinny mieć sens.

Jeśli metody listy standardowej nie mają sensu, obiekt powinien zawierać listę, a nie listę.

W starej pythonowej (2.2?) Podklasowej liście był zły pomysł z różnych przyczyn technicznych, ale w nowoczesnym python jest w porządku.

+4

+1 Tylko dziedziczy, gdy naprawdę ma 100% sensu, w przeciwnym razie utwórz. – delnan

+0

Co do efektów ubocznych, był trochę nieaktualny? Dane znajdują się na liście, ale istnieje wiele innych konkretnych metod, które muszę wyrzucić na wierzch, aby wykonać wiele rzeczy. –

+0

tak, dziedzicz dla relacji "is-a", komponuj dla prawie wszystkiego innego. –

6

Nick ma rację. Ponadto, chociaż nie mogę mówić do Pythona, w innych językach OO (Java, Smalltalk) podklasowanie listy jest złym pomysłem. Powinno się unikać dziedziczenia w ogólności, a zamiast tego stosować kompozycję delegacji.

Zamiast tego tworzysz klasę kontenerów i delegujesz połączenia do listy. Klasa kontenera ma odniesienie do listy, a możesz nawet odsłonić połączenia i zwroty listy w swoich własnych metodach. To dodaje elastyczności i pozwala zmienić implementację (inny typ listy lub strukturę danych) później bez łamania jakiegokolwiek kodu. Jeśli chcesz, aby twoja lista wykonywała różne rzeczy typu list, to twój kontener może to zrobić i użyć prostej listy jako prostej struktury danych. Wyobraź sobie, że masz 47 różnych zastosowań list. Czy na pewno chcesz zachować 47 różnych podklas? Zamiast tego można to zrobić za pomocą kontenera i interfejsów. Jedna klasa do utrzymania i umożliwienia ludziom wywoływania nowych i ulepszonych metod za pośrednictwem interfejsu (interfejsów) z niewystarczającą implementacją.

17

Moduł abstract base classes dostarczony w module collections, w szczególności MutableSequence, może być przydatny podczas implementowania klas podobnych do listy. Są one dostępne w Pythonie 2.6 i nowszych wersjach.

Dzięki ABC możesz wdrożyć "podstawową" funkcjonalność swojej klasy, która zapewni metody, które logicznie zależą od tego, co zdefiniowałeś.

Na przykład, wdrażanie __getitem__ w collections.Sequence pochodzące z A klasy będzie wystarczające, aby zapewnić swoją klasę z __contains__, __iter__ i innych metod.

Nadal możesz chcieć użyć zawartego obiektu listy do ciężkiego podnoszenia.

+1

Od wersji Python 3.3+ został przeniesiony do modułu ['collections.abc'] (https://docs.python.org/3/library/collections.abc.html). – xmedeko

Powiązane problemy