Wie eigene Typen definieren?

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
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hi!

Ich plane mit einer Funktion namens prettify() die Objekte verschiedener anderer Funktionen, welche von diesen immer als Tuple-Liste zurückgegeben werden, lesbarer darzustellen. Hierfür müssten für jedes Listenelement die Elemente eines jeden Tuples mittels String Formattings in eine bestimmte Form gebracht und dann alle Elemente zu einem String zusammengefügt werden, welcher dann zurückgegeben wird. Bisher mache ich das so:

Code: Alles auswählen

def prettify_moods(data):
    s = []
    for elem in data:
        name, string, time, mood = elem
        s.append('<%s> %s <%s>\n%s' % (name, string, time, mood))
    return '\n\n'.join(s)
Ich möchte nun, dass in diesem Fall das Objekt data von der Funktion, die das Objekt zurückgibt (in meinem Fall heißt sie get_moods()) den Typ moods erhält, damit die spätere Funktion prettify() prüfen kann, um welchen Typ es sich handelt und dann entscheidet, wie das entsprechende String Formatting aussehen muss.

Das war quasi die Erklärung für die Frage aus der Überschrift - ich hoffe, es ist nachvollziehbar, was ich vorhabe. :)

Gruß

Sebastian
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Also ich verstehe nicht, was du willst. Suchst du danach?

Code: Alles auswählen

class Mood(object):
    ...

def get_moods():
    return [Mood(), Mood(), ...]

for obj in get_moods():
    if isinstance(obj, Mood):
        ...
Stefan
BlackJack

Deine Frage im Titel geht schon in die richtige Richtung: Deine Objekte sollten selber wissen wie sie "prettified" werden, also musst Du Typen erstellen, die eine entsprechende Methode haben. Eigene Typen erstellt man mit ``class``. Das allgemeine `prettify()` sähe dann ungefähr so aus:

Code: Alles auswählen

def prettify(data):
    return '\n\n'.join(d.prettify() for d in data)
Der Ansatz, den sma da zeigt, ist eher unschön.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

http://pypi.python.org/pypi/simplegeneric

Das dürfte vielleicht passen :)
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:Eigene Typen erstellt man mit ``class``.
Sorry, das habe ich nicht ganze verstanden. Wenn ich die Klasse Test erstelle, hat sie doch immer noch den Typ instance:

Code: Alles auswählen

>>> class Test:
	pass

>>> test = Test()
>>> type(test)
<type 'instance'>
Davon habe ich ja nicht wirklich was. Aber vermutlich meintest du das auch anders...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Eigene Typen definierst du mit ``class``. Eine Klasse ist ein Typ, so einfach ist das. Und jeder Typ weiß, wie man sich darstellt, über ``render``. Oder irgendeine andere Funktion.

Code: Alles auswählen

class RenderingNode(object):
    def render(self):
        return self.content

class Text(RenderingNode):
    def __init__(self, text):
        self.content = text

class Number(RenderingNode):
    def __init__(self, number):
        self.content = number

nodes = [Text("Ich bin"), Number(3), Text("Jahre alt")]
print ' '.join(node.render() for node in nodes)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:


GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Vielleicht verstehe ich euch alle nur falsch, aber ich möchte eigentlich sowas machen können:

Code: Alles auswählen

def prettify(data):
    datatype = type(data)
    if datatype is moods:
        return _prettymoods(data)
    if datatype is bulletins:
        return _prettybulletins(data)
    else:
        raise TypeError, 'Expect moods or bulletins type, not %s' % datatype

def _prettymoods(data):
    hier der selbe inhalt wie oben beschrieben
Und mir ist bisher nicht klargeworden wie ich das umsetzen soll.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Du suchst wohl nach isinstance()?
Und natürlich hat eine Instanz einer Klasse den Typ Instanz ;)
Klassenvergleiche kannst du dann mit isinstance machen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

snafu hat geschrieben:Vielleicht verstehe ich euch alle nur falsch, aber ich möchte eigentlich sowas machen können:
Leonidas variante mit render() ist aber IMHO besser.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

snafu hat geschrieben:Vielleicht verstehe ich euch alle nur falsch, aber ich möchte eigentlich sowas machen können
Das ist aber keine gute idee, da die Render-Logik dann in eine ungebeiligte Funktion verschoben wird, die zudem nicht erweiterbar ist. Meine Variante ermöglicht belibige Erweitarbarkeit, da um es zu rendern nur ein Interface implementiert werden muss, schon funktioniert das Rendern wie mit bereits fertigen Klassen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Das Prinzip, das Leonidas vorgeschlagen hat, ist doch dabei eine wirklich gängige und sinnvolle Lösung. Spontan fällt mir bei Java die toString()-Methode ein, die afaik jedes Objekt besitzt.

Ok, bei Python ja auch fällt mir grad auf :-D

Will man eine eigene Form der Ausgabe überschreibt man eben __str__() oder __repr__() und voila. Nichts anderes wird doch von Dir verlangt, oder?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Habe Leonidas' Tipp nun erfolgreich angewendet: http://paste.pocoo.org/show/85606/

Vielen Danke dafür. :)

Anmerkung: Die fehlenden Klammern in Zeile 53 sind mir später auch aufgefallen und bei mir nun gesetzt. ;)
BlackJack

Nein, Du hast Leonidas' Tipp nicht erfolgreich angewendet. Warum kannst oder willst Du den Klassen, die Du *sowieso schon hast*, keine `prettify()`-Methode verpassen? So wie's jetzt ist, ist es ja noch bescheuerter gelöst als die hässliche Nicht-OOP-Lösung mit Typtests. `Toolbox` ist im Moment vollkommen überflüssig.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:Nein, Du hast Leonidas' Tipp nicht erfolgreich angewendet. Warum kannst oder willst Du den Klassen, die Du *sowieso schon hast*, keine `prettify()`-Methode verpassen? So wie's jetzt ist, ist es ja noch bescheuerter gelöst als die hässliche Nicht-OOP-Lösung mit Typtests. `Toolbox` ist im Moment vollkommen überflüssig.
Hab's in der neuen Version beachtet: http://paste.pocoo.org/show/85627/
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wo denn? Du hast doch schon wieder eine Fallunterscheidung drin (wobei ich das return nach dem if unübersichtlich finde! Ein explizites else ist da irgend wie schöner :) )
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

In prettify könntest du auch pprint.pformat nehmen: http://docs.python.org/dev/library/ppri ... nt.pformat

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Irgendwie check ich das mit den Klassen noch nicht richtig. Ich habe jetzt das hier gebastelt:

Code: Alles auswählen

class Generic(object):

    def get_dict(self):
        """Return a dictionary of given data, expects a list with tuples

        For each tuple: Return first element as key and a tuple of remaining 
        elements as value.

        Example:
        In: [('foo', 'bar', 'baz'), ('ham', 'egg', 'spam')]
        Out: {'foo': ('bar', 'baz'), 'ham': ('egg', 'spam')}

        Intended to ease access on user related data when setting tuples True.
        """
        keys = (elem[0] for elem in self.data)
        values = (elem[1:] for elem in self.data)
        return dict((key, value) for key, value in izip(keys, values))


class Moods(Generic):
    
    def __init__(self, data):
        self.data = data

    def prettify(self):
        """Return a human-readable string of all data"""
        
        data = self.data
        if type(data) is tuple:
            string, time, mood = data
            return '%s <%s>\n%s' % (string, time, mood)
        s = []
        for elem in data:
            name, string, time, mood = elem
            s.append('<%s> %s <%s>\n%s' % (name, string, time, mood))
        return '\n\n'.join(s)
Meine get_moods aus Datagetter erzeugt nun also ein Moods Objekt. Diese Klasse erbt von Generic die Methode get_dict (zumindest glaube ich das). Wenn ich jetzt sage:

Code: Alles auswählen

datagetter = pyspace.Datagetter()
[dann der login...]
moods = datagetter.get_moods()
moods.get_dict()
...dann kommt ein leeres Dict zurück. Verschiebe ich get_dict in die Klasse Moods, funktioniert es wunderbar. Wo liegt der Fehler?
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Code: Alles auswählen

# ...

class Printer(object):
    def printout(self):
        print '...Printer prints something...'

class OtherPrinter(object):
    def printout(self):
        print '...OtherPrinter prints something else...'

class MessagePrinter(object):
    def __init__(self, message):
        self.message = message
    def printout(self):
        print '...MessagePrinter prints "%s"' % (message,)

# ...

object_list = [Printer(), OtherPrinter(), MessagePrinter('Hallo Welt'), Printer()]

for o in object_list:
    o.printout()
Wenn ich das Problem richtig interpretiere, dann sollte oben genanntes Modell genau auf das Problem des OP passen. In C++ würde man eine (abstrakte) Basisklasse mit einer rein virtuellen Methode printout definieren und die Printer davon erben lassen - in Java wären das Interfaces. Soweit ich jetzt richtig informiert bin, ist das in Python nicht nötig.

Grüße... Heiko

EDIT: Einrückung korrigiert (böse Tabs)
Zuletzt geändert von bwbg am Freitag 19. September 2008, 10:16, insgesamt 1-mal geändert.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Code: Alles auswählen

import pprint

def prettify(data):
    return pprint.pformat(data)

def get_dict(data):
    """
    >>> get_dict([('foo', 'bar', 'baz'), ('ham', 'egg', 'spam')])
    {'foo': ('bar', 'baz'), 'ham': ('egg', 'spam')}
    """
    result = {}
    for item in data:
        result[item[0]] = item[1:]
    return result

if __name__ == "__main__":
    import doctest
    doctest.testmod(verbose=False)

    d = get_dict([('foo', 'bar', 'baz'), ('ham', 'egg', 'spam')])
    print prettify(d) # oder gleich pprint.pprint(d) ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten