I want to create a list that can only accept certain types. As such, I'm trying to inherit from a list in Python
Nie jest to najlepsze podejście! Listy w Pythonie mają tak wiele metod mutowania, że musielibyśmy nadpisywać kilka (i prawdopodobnie zapomnielibyśmy o niektórych).
Raczej okład lista, dziedziczą collections.MutableSequence
i dodać kontroli na nielicznych „dławik punktowych” metod, na których opiera MutableSequence
do wdrożenia wszystkich innych.
import collections
class TypedList(collections.MutableSequence):
def __init__(self, oktypes, *args):
self.oktypes = oktypes
self.list = list()
self.extend(list(args))
def check(self, v):
if not isinstance(v, self.oktypes):
raise TypeError, v
def __len__(self): return len(self.list)
def __getitem__(self, i): return self.list[i]
def __delitem__(self, i): del self.list[i]
def __setitem__(self, i, v):
self.check(v)
self.list[i] = v
def insert(self, i, v):
self.check(v)
self.list.insert(i, v)
def __str__(self):
return str(self.list)
oktypes
argument jest normalnie krotką typów, które chcesz zezwolić, ale to jest OK, aby przekazać jeden typ tam oczywiście (i, dokonując że jeden typ abstrakcyjną klasą bazową, ABC, można łatwo przeprowadzić dowolne sprawdzanie typu w ten sposób - ale to inny problem).
Oto niektóre przykładowy kod korzystania z tej klasy:
x = TypedList((str, unicode), 'foo', 'bar')
x.append('zap')
print x
x.append(23)
wyjście jest:
['foo', 'bar', 'zap']
Traceback (most recent call last):
File "tl.py", line 35, in <module>
x.append(23)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_abcoll.py", line 556, in append
self.insert(len(self), value)
File "tl.py", line 25, in insert
self.check(v)
File "tl.py", line 12, in check
raise TypeError, v
TypeError: 23
Uwaga zwłaszcza że mamy nie nadpisane append
- jeszcze dołączyć tam jest i zachowuje się tak samo zgodnie z oczekiwaniami.
nie-tak-tajemnica, że nieco magii objawia się w traceback: _abcoll.py
(moduł Implementacja abstrakcyjnych klas bazowych w module collections
), na linii 556, narzędzia dołączyć wywołując naszych insert
- - które my ma, oczywiście, poprawnie przesłonięte.
Ten "szablonowy wzór metody projektowania" (absolutnie cenny dla wszystkich rodzajów OOP - spójrz na moje przemówienia na temat wzorców projektowych na youtube, a dowiesz się dlaczego ;-), między innymi zaletami, daje nam "dławik" efekt punktowy "Wspominałem wcześniej: dodając kilka sprawdzeń na bardzo niewielu metodach, które musisz zastosować, zyskujesz przewagę, że te sprawdzenia odnoszą się do _all__ innych odpowiednich metod (a zmienne sekwencje w Pythonie mają ich wiele ;-).
Nic dziwnego, że otrzymujemy bardzo mocny i klasyczny wzór "za kulisami", ponieważ cała idea stojąca za tą strategią wdrożenia pochodzi wprost z nieśmiertelnej klasycznej książki "Wzorcowe wzory" (której autorzy często zbiorczo określany jako gang czterech ";-): preferują kompozycję obiektu nad dziedziczeniem. Dziedziczenie (z klas konkretnych) jest bardzo sztywnym mechanizmem sprzęgającym, pełnym" gotchas ", gdy tylko próbujesz go użyć do rób wszystko, nawet odrobinę poza rygorystycznymi ograniczeniami, kompozycja jest niezwykle elastyczna i użyteczna, a dziedziczenie z odpowiednich klas abstrakcyjnych może bardzo ładnie ukończyć obrazek:
Doskonały "Effective C++" Scotta Meyersa, item 33, jeszcze silniej: sprawiają, że klasy inne niż liść są abstrakcyjne. Skoro przez słowo "non-leaf" oznacza "dowolną klasę, która kiedykolwiek została odziedziczona", równoważne sformułowanie byłoby "nigdy nie odziedziczone po konkretnej klasie".
Scott pisze w kontekście C++, oczywiście, ale Paul Haahr daje dokładnie te same informacje dla Javy, sformułowane jako Nie podklasa konkretne zajęcia - i generalnie drugi go dla Pythona, choć nie faworyzują łagodniejsze sformułowanie "gang-of-four", wolą dziedziczenie kompozycji (klasy betonu) (ale rozumiem, że zarówno Scott, jak i Paul często piszą dla publiczności, która potrzebuje bardzo bezpośrednich i silnie sformułowanych rad, niemal sformułowanych jako "przykazania" zamiast porady, nie łagodniej sformułowane, które mogą zbyt łatwo zignorować w imię ich wygody ;-).
Dzięki za pomoc! – chaindriver