Seite 1 von 1
Elemente einer hierarchischen Listenstruktur annotieren
Verfasst: Mittwoch 7. Januar 2009, 18:23
von lucia
Hallo

Ich möchte, Elemente in einer hierarchischen Listenstruktur mit ihrem jeweiligen Python-Typ annotieren. Nur klappt das mit dem hierarchisch leider nicht.
Code: Alles auswählen
>>> for e in [8, "a", [(2,3), "die katze", 0], 2+3]:
print (type(e), e)
(<type 'int'>, 8)
(<type 'str'>, 'a')
(<type 'list'>, [(2, 3), 'die katze', 0])
(<type 'int'>, 5)
Ich würde gerne die Liste in der Liste als Tupel, String und Integer angezeigt bekommen. Hat jemand einen Tipp für mich?
Entschuldigung wegen des sehr uneleganten Stils, blutige Anfängerin

Verfasst: Mittwoch 7. Januar 2009, 18:33
von derdon
Code: Alles auswählen
In [60]: for e in [8, "a", [(2,3), "die katze", 0], 2+3, {'zahl': 23, 'sinn_des_lebens': 42}]:
if isinstance(e, (list, tuple)):
for item in e:
print (type(item), item)
elif isinstance(e, dict):
for value in e.itervalues():
print (type(value), value)
else:
print (type(e), e)
....:
....:
(<type 'int'>, 8)
(<type 'str'>, 'a')
(<type 'tuple'>, (2, 3))
(<type 'str'>, 'die katze')
(<type 'int'>, 0)
(<type 'int'>, 5)
(<type 'int'>, 42)
(<type 'int'>, 23)
Mit
isinstance kann man prüfen, ob ein Objekt von der vermuteten Klasse instanziiert wurde. list, int, type, dict, ... sind nämlich auch nichts anderes als Klassen.
Edit: @lucia: habe ich dich falsch verstanden?
Verfasst: Mittwoch 7. Januar 2009, 18:37
von Leonidas
derdon, da würde man eher erst prüfen ob es ein dict ist und dann ein ``iteritems()`` machen, dann würde man versuchen ob es iterierbar ist (es gibt durchaus iterierbare Typen die keine Listen oder Tupel sind) und erst wenn auch das fehlschlägt, dann den Typ vom Objekt nehmen. Wenn beim dict auch nur die Keys reichen, kann man das mit den Iterables zusammenlegen.
Ggf würde man hier sogar rekursiv vorgehen, wenn die Liste wiederrum eine Liste enthält, etc.
Verfasst: Mittwoch 7. Januar 2009, 18:49
von lucia
Im Grunde möchte ich anstatt
Code: Alles auswählen
(<type 'int'>, 8)
(<type 'str'>, 'a')
(<type 'list'>, [(2, 3), 'die katze', 0])
(<type 'int'>, 5)
folgendes bekommen:
Code: Alles auswählen
(<type 'int'>, 8)
(<type 'str'>, 'a')
(<type 'tuple'>, (2,3))
(<type 'str'>, 'die katze')
(<type 'int'>, 0)
(<type 'int'>, 5)
Ich würde mich gerne spezifischer ausdrücken,
aber dafür fehlt mir wohl noch das Fachvokabular, sorry

Verfasst: Mittwoch 7. Januar 2009, 18:50
von audax
Code: Alles auswählen
IGNORE = (basestring, tuple)
def deepmap(func, itr):
if isinstance(itr, IGNORE):
return (func(itr), itr)
else:
try:
return [deepmap(func, elem) for elem in itr]
except TypeError:
return func(itr)
def annotate(elem):
return (type(elem), elem)
test = [8, "a", [(2,3), "die katze", 0], 2+3]
print deepmap(annotate, test)
Das ergibt:
Code: Alles auswählen
[(<type 'int'>, 8), ((<type 'str'>, 'a'), 'a'), [((<type 'tuple'>, (2, 3)), (2, 3)), ((<type 'str'>, 'die katze'), 'die katze'), (<type 'int'>, 0)], (<type 'int'>, 5)]
Verfasst: Mittwoch 7. Januar 2009, 18:54
von audax
Und nochmal ganz anders:
Code: Alles auswählen
def deepmap(func, itr, ignore=None):
if itr is ignore:
return (func(itr), itr)
else:
try:
return [deepmap(func, elem, itr) for elem in itr]
except TypeError:
return func(itr)
def annotate(elem):
return (type(elem), elem)
test = [8, "a", [(2,3), "die katze", 0], 2+3]
print deepmap(annotate, test)
Er schaut sich jetzt _jedes_ iterable an, verfällt aber nicht in eine Endlosschleife.
Verfasst: Mittwoch 7. Januar 2009, 18:56
von numerix
lucia hat geschrieben:Im Grunde möchte ich anstatt
Code: Alles auswählen
(<type 'int'>, 8)
(<type 'str'>, 'a')
(<type 'list'>, [(2, 3), 'die katze', 0])
(<type 'int'>, 5)
folgendes bekommen:
Code: Alles auswählen
(<type 'int'>, 8)
(<type 'str'>, 'a')
(<type 'tuple'>, (2,3))
(<type 'str'>, 'die katze')
(<type 'int'>, 0)
(<type 'int'>, 5)
Ich würde mich gerne spezifischer ausdrücken,
aber dafür fehlt mir wohl noch das Fachvokabular, sorry

Wie das geht, ist doch eben gezeigt worden, oder übersehe ich jetzt was?

Verfasst: Mittwoch 7. Januar 2009, 19:01
von derdon
Leonidas hat Recht, diese Aufgabe schreit geradezu nach Rekursion. Wer möchte der erste sein?
Edit: Sorry, audax. Hab mir deinen Code ehrlich gesagt nicht so genau angeguckt.
Verfasst: Mittwoch 7. Januar 2009, 19:03
von audax
Ich fühl mich ignoriert.
Also gut, jetzt noch geflattet:
Code: Alles auswählen
def annotate_list(itr):
if isinstance(itr, list):
return [annotate_list(elem) for elem in itr]
else:
return (type(itr),itr)
def flatten(x):
""" http://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks """
result = []
for el in x:
if hasattr(el, "__iter__") and \
not isinstance(el, (tuple, basestring)):
result.extend(flatten(el))
else:
result.append(el)
return result
test = [8, "a", [(2,3), "die katze", 0], 2+3]
print flatten(annotate_list(test))
Ergebnis:
Code: Alles auswählen
[(<type 'int'>, 8), (<type 'str'>, 'a'), (<type 'tuple'>, (2, 3)), (<type 'str'>, 'die katze'), (<type 'int'>, 0), (<type 'int'>, 5)]
Verfasst: Mittwoch 7. Januar 2009, 19:03
von DasIch
audax Lösung ist rekursiv.
Verfasst: Mittwoch 7. Januar 2009, 19:13
von lucia
@audax: Wow, das ist genau das Ergebnis, das ich haben wollte. Vielen, lieben Dank.
Ich versuch' mich jetzt mal durch den Code zu kämpfen, um es auch verstehen.
Vielen Dank für die schnelle Hilfe!