2015-07-22 8 views
7

Ich möchte eine Klasse in Python mit verschiedenen Attributen und Methoden erstellen, aber um die Funktionalität einer Liste zu erben, so dass ich Objekte an das Objekt selbst und nicht an seine Attribute anhängen kann. Ich möchte "graph[3]" anstatt "graph.node_list[3]" sagen können. Gibt es eine Möglichkeit, dies zu tun?Wie mache ich eine Klasse, die auch eine Liste ist?

+3

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

Antwort

10

Alles, was Sie wirklich tun müssen, ist eine

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 

Nachtrag __getitem__ bieten: Es gibt andere Methoden, die Sie wahrscheinlich auch zur Verfügung stellen möchten. __len__ ist definitiv einer von ihnen. Es gibt eine ziemlich lange Liste von magischen Methoden, ich würde empfehlen, sie durchzugehen und diejenigen auszuwählen, die Sinn ergeben.

+0

Man kann auch von' abc.Sequence' ableiten, um Typüberprüfungen zu besänftigen. Oder implementieren Sie zumindest '__len__' ... – refi64

+0

@ kirbyfan64sos, Dank der virtuellen Unterklassen müssen Sie nicht von irgendwelchen' collections' 'abc's erben, außer Sie wollen ihre Methoden erben. – Navith

+1

@Navith Ich bezog mich auf Typüberprüfer wie Mypy. :) – refi64

5

Sie können nur erben von list:

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

Aber Subklassen builtin Typen nicht unbedingt eine gute Idee ist.


collections.abc.Sequence (oder seit 3.5, typing.Sequence[T]) ist die Art, wie ich es tun würde.

+1

"Das ist nicht unbedingt eine gute Idee." - Beziehen Sie sich auf den ersten Ansatz oder auf den zweiten? Warum ist es auch nicht eine gute Idee? – alfasin

+0

@alfasin Unterklasse eingebaute Typen ist in der Regel keine gute Idee. – o11c

+1

Warum ist es nicht eine gute Idee? – alfasin

1

Da Python duck typing verwendet, der Hauptunterschied zwischen einer Liste aus, und jedem anderen Objekt ist der Satz von Methoden es aussetzt. Sie können die primären Attribute (Methoden und Felder) eines Objekts mit der Funktion dir() leicht sehen.

>>> [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'] 

Offensichtlich gibt es viele Methoden, die hier, und Sie wahrscheinlich kümmern sich nicht um die meisten von ihnen. Wenn Sie jedoch das Verhalten einer Liste wirklich replizieren möchten, möchten Sie sie wahrscheinlich implementieren. Die meisten der __...__ Methoden sind in Pythons definiert, wenn Sie sie nachschlagen möchten.

Von dieser Seite:

Mutable Sequenzen Methoden bieten sollten append(), count(), index(), extend(), insert(), pop(), remove(), reverse() und sort(), wie Python-Standardlistenobjekte. Schließlich sollten die Sequenztypen Addition (dh Verkettung) und Multiplikation (dh Wiederholung) implementieren, indem sie die unten beschriebenen Methoden definieren: __add__(), __radd__(), __iadd__(), __mul__(), __rmul__() und __imul__(); Sie sollten keine anderen numerischen Operatoren definieren. Es wird empfohlen, dass beide Zuordnungen und Sequenzen die __contains__()-Methode implementieren, um eine effiziente Verwendung des in-Operators zu ermöglichen; Für Mappings sollte In die Schlüssel des Mappings durchsuchen. Für Sequenzen sollte es die Werte durchsuchen. Es wird außerdem empfohlen, dass beide Zuordnungen und Sequenzen die __iter__()-Methode implementieren, um eine effiziente Iteration durch den Container zu ermöglichen. Für Zuordnungen sollte __iter__() dasselbe wie keys() sein; Für Sequenzen sollte es die Werte durchlaufen.

Die Funktion, über die Sie insbesondere nach Indexnachfragen fragen, wird von __getitem__ bereitgestellt. Ich würde vorschlagen, auch __contains__() und __iter__() (und vielleicht __len__()) zu implementieren, zumindest.

Verwandte Themen