2009-05-29 4 views
2

Ich möchte eine Klasse definieren, die __getitem__ unterstützt, aber keine Iteration erlaubt. zum Beispiel:Wie kann ich eine Klasse in Python Unterstützung __getitem__ machen, aber Iteration nicht zulassen?

class B: 
    def __getitem__(self, k): 
     return k 

cb = B() 

for x in cb: 
    print x 

Was könnte ich in die Klasse hinzufügen B um die for x in cb: zu zwingen, zum Scheitern verurteilt?

+0

Genau dies zu fragen, und beantwortet sie, falls jemand anderes wissen muss, wie dies zu tun. – grieve

+3

Aus Neugier, * warum * willst du Zugang zu getitem geben, aber nicht iterierbar machen? Was war dein Anwendungsfall? –

+1

Ich habe eine Klasse, die sich wie ein Wörterbuch verhält, aber nicht erbt. Daher definiere ich __getitem__, und wenn jemand versucht, darüber zu iterieren, will ich einen Fehler, anstatt zu versuchen, __getitem__ mit ganzen Zahlen aufzurufen. Nur um klar zu sein, so hätte ich diese spezielle Klasse nicht gewählt, aber meine Entscheidung wurde außer Kraft gesetzt. – grieve

Antwort

14

ich denke, etwas bessere Lösung wäre, einen TypeError statt einer einfachen Ausnahme auszulösen (was normalerweise bei einer nicht iterierbaren Klasse der Fall ist):

class A(object): 
    # show what happens with a non-iterable class with no __getitem__ 
    pass 

class B(object): 
    def __getitem__(self, k): 
     return k 
    def __iter__(self): 
     raise TypeError('%r object is not iterable' 
         % self.__class__.__name__) 

Testing:

>>> iter(A()) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'A' object is not iterable 
>>> iter(B()) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "iter.py", line 9, in __iter__ 
    % self.__class__.__name__) 
TypeError: 'B' object is not iterable 
+0

+1 für die ordnungsgemäße Verwendung von New-Style-Klassen (sowie die allgemeine Güte des Ansatzes). –

+1

Leider macht dies isinstance (a, collections.Iterable) zurück True :( – UncleZeiv

2

Aus den Antworten auf diese question, können wir sehen, dass __iter__ vor __getitem__ aufgerufen wird, wenn es vorhanden ist, so einfach B definieren als:

class B: 
    def __getitem__(self, k): 
     return k 

    def __iter__(self): 
     raise Exception("This class is not iterable") 

Dann:

cb = B() 
for x in cb: # this will throw an exception when __iter__ is called. 
    print x 
+0

Wenn es eine pythonalere Antwort als diese gibt, würde ich es gerne akzeptieren. – grieve

+2

haben Sie Klassenname richtig großgeschrieben, das wäre mehr Python – SilentGhost