nach Iterierbarkeit fragen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Wie frage ich bloß, ob ein Objekt X iterierbar ist oder nicht? Ein eingebautes "isiterable(X)" gibt es anscheinend nicht, oder habe ich etwas übersehen?
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Wozu? Der bevorzugte Weg ist, einfach anzunehmen das es iterierbar ist. Sollte das nicht der Fall sein bekommt man eine nette Exception. Ansonsten kannst du auch hasattr(obj, "__iter__") benutzen, aber manche Objekte sind auch iterable, wenn sie __iter__ nicht besitzen - diese Objekte haben eine __len__ + __getitem__ Methode und werden von iter() dann mit den entsprechenden range() Werten gefüttert. IIRC sollte dieses Verhalten aber in Python 3 verschwunden sein (richtig?).
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Oder vielleicht so etwas?

Code: Alles auswählen

def isiterable(X):
  try:
    for x in X: break
    return True
  except TypeError:
    return False
Ich möchte gleich am Anfang eines Funktionsaufrufes testen können, ob die Argumente der Funktion sinnvoll sind oder nicht, und möchte nicht erst lange warten und Daten durcheinanderwürfeln, bevor die Exception kommt.
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

Goswin hat geschrieben:Oder vielleicht so etwas?

Code: Alles auswählen

def isiterable(X):
  try:
    for x in X: break
    return True
  except TypeError:
    return False
Ich möchte gleich am Anfang eines Funktionsaufrufes testen können, ob die Argumente der Funktion sinnvoll sind oder nicht, und möchte nicht erst lange warten und Daten durcheinanderwürfeln, bevor die Exception kommt.
Bloederweise verbrauchst du so ein element des Iterators. In Python prueft man die Argumente normalweise nicht, sondern lasst die exception einfach dann raisen wann sie kommt.
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Statt tatsächlich darüber zu iterieren sollte man versuchen mit iter() einen Iterator zu erzeugen.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

str1442 hat geschrieben:diese Objekte haben eine __len__ + __getitem__ Methode und werden von iter() dann mit den entsprechenden range() Werten gefüttert. IIRC sollte dieses Verhalten aber in Python 3 verschwunden sein (richtig?).
`__len__` ist nicht nötig. Python versucht einfach `__getitem__` mit numerischen Indizes beginnend mit 0 und dann aufsteigend so lange aufzurufen, bis es zu einem IndexError kommt. Dieses Verhalten ist auch noch in Python 3.x dokumentiert.

Stefan
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Schön, dann hätte ich ja schon 2 Alternativen, wofür ich mich vielmals bedanke:

Code: Alles auswählen

def isiterable(X):
  return hasattr(X,'__iter__')

Code: Alles auswählen

def isiterable(X):
  try: iter(X); return True
  except TypeError: return False
Die erste Alternative ist laut str1442 weniger gut für Python_2.x, und laut sma wird das in Python_3.x anscheinend nicht anders sein. Sollen wir die zweite Alternative zum Gewinner erklären?
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ja, wenn man den SyntaxError behebt und nicht so mit Zeilen geizt.
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Code: Alles auswählen

def isiterable(X):
  try: iter(X); return True
  except TypeError: return False
@Dasich:
Ich habe den Code getestet und er scheint bei Python_2.5 einwandfrei zu funktionieren. Hat er einen Syntaxfehler von Python_3.x?
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

Schrecklich aussehen tut er trotzdem.
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Als Parameter würde ich obj statt X nehmen.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Hab dass mit dem Semikolon falsch interpretiert. Trotzdem ist 3 Zeilen in eine zu pressen kein Zeichen von sonderlich schönem Code. Wenn man sowas wie try except, if elif else o.ä. hat macht dies den Code deutlich schwerer zu lesen.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Goswin hat geschrieben:Hat er einen Syntaxfehler von Python_3.x?
Nein.
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

Python > 3.0 hat definitiv kein hasattr() mehr, dort läufts über getattr(obj, '__name__').
[url=http://www.proandkon.com]proandkon.com[/url]
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

mzh hat geschrieben:Python > 3.0 hat definitiv kein hasattr() mehr, dort läufts über getattr(obj, '__name__').

Code: Alles auswählen

Python 3.0.1 (r301:69556, Feb 22 2009, 14:12:04)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> hasattr
<built-in function hasattr>
Da muss ich wohl ein anderes Python haben.
mzh
User
Beiträge: 295
Registriert: Dienstag 3. März 2009, 15:27
Wohnort: ZH

Hm, keine Ahnung, wie ich darauf gekommen bin..
Ah, ich meinte callable.
[url=http://www.proandkon.com]proandkon.com[/url]
BlackJack

@Goswin: Die zweite Variante ist genauso unzuverlässig wie die erste, denn ein Objekt das eine `__getitem__()`-Methode besitzt, aber nicht "iterable" ist, hat kein Problem mit dem `iter()`-Aufruf. Auch da "kracht" es erst, wenn man versucht von dem Iterator das erste Element zu holen.

Was letztendlich bedeutet, dass man nicht wirklich auf "iterable" prüfen kann, ohne das Objekt einfach so zu verwenden.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Ab Python 2.6 geht das auch so:

Code: Alles auswählen

from collections import Iterable

class Foo(object):
    def __iter__(self):
        pass

isinstance(list(), Iterable)
# True
isinstance(dict(), Iterable)
# True
isinstance(Foo(), Iterable)
# True
Gruß,
Manuel
BlackJack

@helduel: Aber auch bei 2.6 erkennt man so nicht alle "iterables":

Code: Alles auswählen

>>> class A(object):
...   def __getitem__(self, i):
...     if i > 5:
...       raise StopIteration()
...     else:
...       return i
...
>>> a = A()
>>> isinstance(a, Iterable)
False
>>> [x for x in a]
[0, 1, 2, 3, 4, 5]
Man muss es halt einfach probieren.
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

name hat geschrieben:Schrecklich aussehen tut er [dein Code] trotzdem.
DasIch hat geschrieben:3 Zeilen in eine zu pressen [ist] kein Zeichen von sonderlich schönem Code. Wenn man sowas wie try except, if elif else o.ä. hat macht dies den Code deutlich schwerer zu lesen.
Am Anfang war Python noch script und stur,
da schuf BDFL das Semikolon und sprach:

"Zieh hinaus in alle Module und vermehre dich,
und sammelt um euch die Kleinen unter den Befehlen,
auf dass sie eng zusammenstehen
und ich sie gut übersehen kann"
Und da zogen Semikola ein in Klassen und Methoden,
und sammelten um sich die breaks und die returns,
und alle verwaisten x+=1 und list.sort(),
ein jegliches in seine vorangehende Codezeile.

Und BDFL sah, dass das Semikolon gut war,
und es wurde aus Alfa und Beta die Version t+1.

:wink:
Antworten