2015-07-22 16 views
7

Chcę utworzyć klasę w języku Python z różnymi atrybutami i metodami, ale aby dziedziczyła ona funkcjonalność listy, dzięki czemu mogę dołączać obiekty do samego obiektu, a nie do jego atrybutów. Chcę móc powiedzieć "graph[3]" zamiast "graph.node_list[3]". Czy jest jakiś sposób na zrobienie tego?Jak utworzyć klasę, która również jest listą?

+3

Podaj ['__getitem__'] (https://docs.python.org/2/reference/datamodel.html#object.__getitem__) – NightShadeQueen

Odpowiedz

10

Wszystko, co naprawdę trzeba zrobić, to zapewnić __getitem__

In [1]: class Foo: 
    ...:  def __init__(self, *args): 
    ...:   self.args = args 
    ...:  def __getitem__(self, i): 
    ...:   return self.args[i] 
    ...:  

In [2]: c = Foo(3,4,5) 

In [3]: c[2] 
Out[3]: 5 

In [4]: c[3] 
IndexError: tuple index out of range #traceback removed for brevity 

In [5]: for i in c: print(i) #look, ma, I can even use a for-loop! 
3 
4 
5 

Uzupełnienie: Istnieją inne metody prawdopodobnie chcesz, aby zapewnić, too. __len__ jest zdecydowanie jednym z nich. Jest dość długa lista magicznych metod, polecam je przejrzeć i wybrać te, które mają sens.

+0

Można również czerpać z' abc.Sequence', aby poprawić sprawdzanie typu. Lub przynajmniej zaimplementuj '__len__' ... – refi64

+0

@ kirbyfan64sos, Dzięki podklasie wirtualnej, nie musisz dziedziczyć z żadnego z' zbiorów' 'abc, chyba że chcesz dziedziczyć swoje metody. – Navith

+1

@Navith Miałem na myśli sprawdzanie typu, takie jak Mypy. :) – refi64

5

można tylko dziedziczyć list:

class Foo(list): 
    def __init__(self): 
     pass 

Ale instacji wbudowanych typów niekoniecznie jest dobrym pomysłem.


collections.abc.Sequence (lub od 3,5, typing.Sequence[T]) jest sposób, by to zrobić.

+1

"To niekoniecznie dobry pomysł." - Czy odnosisz się do pierwszego podejścia, czy do drugiego? Dlaczego nie jest to dobry pomysł? – alfasin

+0

Typy wbudowane w podfazę typu "haalfasin" zwykle nie są dobrym pomysłem. – o11c

+1

Dlaczego nie jest to dobry pomysł? – alfasin

1

Ponieważ Python używa duck typing, podstawową różnicą między listą a jakimkolwiek innym obiektem jest zestaw metod, które on eksponuje. Możesz łatwo zobaczyć podstawowe elementy (metody i pola) obiektu za pomocą funkcji dir().

>>> [a for a in dir([]) if callable(getattr([], a))] 
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', 
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', 
'__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', 
'__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', 
'__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort'] 

Oczywiście jest tu wiele metod i prawdopodobnie nie dba się o większość z nich. Ale jeśli twoim celem było naprawdę powielać zachowanie listy, prawdopodobnie chcesz je zaimplementować. Większość metod __...__ jest zdefiniowanych w Pythonie data model, jeśli chcesz je sprawdzić.

Od tej strony:

Zmienne sekwencje powinny dostarczyć metod append(), count(), index(), extend(), insert(), pop(), remove(), reverse() i sort(), jak Python Standardowa lista obiektów. Na koniec, typy sekwencji powinny implementować dodawanie (czyli konkatenację) i mnożenie (co oznacza powtarzanie) przez definiowanie opisanych poniżej metod; nie powinni definiować innych operatorów numerycznych. Zaleca się, aby oba odwzorowania i sekwencje implementowały metodę __contains__(), aby umożliwić efektywne wykorzystanie operatora in; dla odwzorowań, w powinno przeszukiwać klucze mapowania; dla sekwencji, powinien przeszukać wartości. Ponadto zaleca się, aby oba odwzorowania i sekwencje implementowały metodę __iter__(), aby umożliwić wydajną iterację przez pojemnik; dla odwzorowań, __iter__() powinno być takie samo jak keys(); w przypadku sekwencji powinien on iterować przez wartości.

Funkcja, o którą pytasz w szczególności, wyszukiwanie indeksu, jest dostępna pod numerem __getitem__. Sugerowałbym również wdrożenie co najmniej __contains__() i __iter__() (i może __len__()).

Powiązane problemy