Python 3.0 Formatierte Print-Frage

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.
Antworten
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Forumfreunde

Habe mich das erste Mal mit Python 3.0 beschäftigt und musste mit Entsetzen feststellen, dass ich die Sprache neu lernen muss.

Wie schreibt man neu in Python 3.0:

Code: Alles auswählen

print "%3.3i " % row_adr + dot_row
Es ist sicher schon viel Dokumentation auf dem Web verfügbar, aber die Sucherei nach einer gezielten Antwort ist zermürbend.

Danke im Voraus für einenTipp

Gruss wuf :wink:
Take it easy Mates!
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Liest denn niemand mehr die Dokumentation?

Sollte es nicht inzwischen bei dem letzten angekommen sein, dass "print" ab Python 3.0 eine Funktion ist und Klammern erwartet?

Das kann doch alles nicht so schwer sein?!

Code: Alles auswählen

print("%i" % i)
Stefan

PS: Dein Ausdruck funktioniert nicht unter 2.x, wenn du das "+" nicht klammerst und "dot_row" auch eine Zahl ist.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Dein Code ist nicht einmal unter Python 2.x lauffähig ;-)

Und alles neu lernen ist nun wirklich übertrieben. Die Änderungen kannst du hier nachlesen.

Was das "print" angeht: dies ist nun eine Funktion. Du musst nun also einfach Klammern um die Parameter setzen. Für die Feinheiten wirfst du am besten einen Blick in die Dokumentation.

Sebastian
pudeldestodes
User
Beiträge: 65
Registriert: Samstag 9. Juni 2007, 23:45

Naja, das "What's new in Python 3.0"-Dokument finde ich nicht ganz perfekt. Wenn man nicht die ganze PEP 3101 zu "A New Approach To String Formatting" lesen möchte, muss man erst unter "What's new in Python 2.6" schauen und dort findet man dann einen kleinen Überblick: PEP 3101: Advanced String Formatting.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sma hat geschrieben:Liest denn niemand mehr die Dokumentation?
Nein, die ist englisch und das ist viel zu kompliziert. SCNR

@pudeldestodes: Das mag ja sein, wobei es durchaus verständlich ist denn 3.0 ist der Nachfolger von 2.6 und nicht von 2.5 und die Formatierung war in 2.6 neu, nicht in 3.0. Außerdem geht es hier um die normale ``printf()``-Syntax die weiterhin verfügbar ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
querdenker
User
Beiträge: 424
Registriert: Montag 28. Juli 2003, 16:19
Wohnort: /dev/reality

@Leonidas: Sollst du immer so :twisted: sein?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

querdenker hat geschrieben:@Leonidas: Sollst du immer so :twisted: sein?
Nö, nur wenn es sich gerade anbietet und das bietet sich hier perfekt an. Immerhin war nicht ich es der jemandem vorgeworfen hat, die Dokumentation nicht gelesen zu haben sondern sma, der argumentiert hat warum englische Doku nicht gelesen wird und die einzige Python 3.0 Dokumentation ist momentan auf Englisch aus genau den Gründen die ich beschrieben habe.

Vielleicht kann man mir zumindest positiv anrechnen, dass ich auch etwas konstruktives zu pudeldestodes gesagt habe, das Posting also nicht völlig unnötig war? Vermutlich nicht, aber dafür weißt du ja was ich heute noch machen werde ;) Und, ooch, ein bischen Humor darf ich doch auch bei der Leserschaft vorraussetzen.
Zuletzt geändert von Leonidas am Montag 12. Januar 2009, 13:30, insgesamt 1-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
pudeldestodes
User
Beiträge: 65
Registriert: Samstag 9. Juni 2007, 23:45

Leonidas hat geschrieben:Außerdem geht es hier um die normale ``printf()``-Syntax die weiterhin verfügbar ist.
The plan is to eventually make this the only API for string formatting, and to start deprecating the % operator in Python 3.1.
Aber du hast natürlich Recht, die alte Syntax ist weiterhin verfügbar. Das hatte ich falsch in Erinnerung.

Einen Link zu dem von mir verlinkten Abschnitt gibt es übrigens doch in dem 3.0er-Dokument, wenn auch ein wenig "versteckt".
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

pudeldestodes hat geschrieben:Aber du hast natürlich Recht, die alte Syntax ist weiterhin verfügbar. Das hatte ich falsch in Erinnerung.
Keine Sorge, das wusste ich bis eben auch nicht da es mir eigentlich logisch erscheinen würde bei 3.0 gleich die neue String-Formatting-Syntax durchzusetzen. Ich muss aber auch zugeben, dass ich nicht weiß ob ich die neue Syntax mag - für die aktuelle spricht zumindest, dass sie so fast in jeder Sprache die String-Formatting hat, einschließlich Python 2.x in sehr ähnlicher Form vorkommt (eine mir bekannte Ausnahme bildet da Common Lisp, was ``~buchstabe``-Syntax verwendet).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

Die neue Syntax hat Guido bei C# gesehen und sich verliebt. Sollte also auch ausserhalb von Python dem ein oder anderen bekannt sein.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@sma: Danke für deinen Vorschlag. Er Funktioniert einwandfrei. Dachte nicht das es so einfach ist. Das die print-Anweisung in Python3.0 ein Funktion ist wusste ich. Es war mehr die Stringformatierung die mich durcheinanderbrachte. Ich lies mich einmal bei einem anderen Beitrag belehren. Dort gab es folgendes:

Die folgend Anweisung:

Code: Alles auswählen

'Got {0} by thread-{1}'.format(n, thread)
entspricht:

Code: Alles auswählen

'Got %i by thread-%i' % (n, thread)
Aus diesem Grunde dachte ich mir die Standard-Stringformatierung wurde in Python3.0 entgültig beerdigt, was ich als eine Zerstümmelung des bisherigen Python-Syntax betrachtete. Da bin ich beruhigt, dass die normale ``printf()``-Syntax weiterhin verfügbar bleibt.

P.S. Stimmt so wie du es dargestellt hast ist es wirklich nicht so schwer. Ich hoffe ich bin der letzte der dich mit dieser Frage belastet habe!

@sam & EyDu: Stimmt. Die Code-Zeile die ich hier präsentierte funktioniert so auch unter Python 2.x nicht :wink:

Ich habe diese Zeile aus einem Code-Abschnitt herauskopiert. Dieser Code-Abschnitt sieht wie folgt aus:

Code: Alles auswählen

    def output_dot_model():
        """Ausgabe des Raster-Models"""

        dot_row = ''
        row_adr = 0
        for y in xrange(app_base.dot_model.height):
            for x in xrange(app_base.dot_model.width):
                if app_base.dot_model.dots[y][x].state:
                    dot_row += '+'
                else:
                    dot_row += '-'
            print "%3.3i " % row_adr + dot_row
            dot_row = ''
            row_adr += 1
Ich sehe die Zeile 12 ist nicht sauber aber es wird keine Exception ausgelöst.

Der Output dieses Code-Abschnittes sieht auf der Konsole wie folgt aus:

Code: Alles auswählen

000 --------------------------------
001 --------------------------------
002 --------------------------------
003 --------------------------------
004 ----------------+---------------
005 --------------------------------
006 --------------------------------
007 --------------------------------
@Leonidas & BlackJack: Mit der englischen Dokumentation habe ich zeitweise auch meine Mühe.

Ich Danke euch allen für eure geduldige Unterstützung und klärenden Worte.

Gruss wuf :wink:
Take it easy Mates!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

wuf hat geschrieben: Ich sehe die Zeile 12 ist nicht sauber aber es wird keine Exception ausgelöst.
Ich bin davon ausgegangen, dass auch "dot_row" ein Integer ist. Mit einem String funktioniert dies dann natürlich.

Die Zeile funktioniert dann übrigens wegen der höheren Priorität ("Prioritäten und mehrere passt irgendwie nicht^^") des %-Operators. Es wird also erst der String formatiert und dann der andere hinten rangehängt.

Sebastian
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Auch wenn die bisherige Syntax zur Zeichenkettenformatierung in Python 3.0 noch gültig ist, meine ich gelesen zu haben, dass damit zu rechnen sei, dass diese ab 3.1 als "deprecated" gezeichnet werden sollte/könnte.

Somit ist es IMHO eine Überlegung wert, ob man den Umstieg auf Python 3.0, der ja eine Reihe von Änderungen mit sich bringt, nicht gleich auch nutzen sollte, sich an die "neue Formatierung" mittels format()-Methode zu gewöhnen.
BlackJack

@wuf: Was ist denn `app_base.dot_model.dots` für ein Typ? Das sieht verdächtig nach unnötiger Verwendung von Indexzugriffen aus.

`row_adr` und `y` dürften immer den gleichen Wert haben, also ist eines davon überflüssig.

Wenn man `dot_row` am Anfang der äusseren Schleife an '' bindet, braucht man das nur an *einer* Stelle machen und nicht schon einmal vor den Schleifen.

Und der Ausdruck `app_base.dot_model.dots[y][x].state` "riecht" danach, dass diese Funktionalität vielleicht eher in die Verantwortung des `app_base.dot_model`-Objekts fällt.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@BlackJack: `app_base.dot_model.dots` ist eine Liste mit Objekten

Hier mehr Code (Ist immer noch ein Prototyp):

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Python 2.6

class Dot(object):
    """Klasse: Rasterfeld"""

    def __init__(self, state=False):
        """Konstruktor für die Klasse Dot"""

        self.state = state

class DotModel(object):
    """Klasse: DOGM-LCD-Logic"""

    DOT_SIZE = 10       # Seitenlänge in Pixels
    LCD_WIDTH = 32 #128     # Raster
    LCD_HEIGHT = 8 #64     # Raster

    #~~ Gibt die Anzahl x-Raster-Felder (Spalten) zurück
    @property
    def width(self):
        return len(self.dots[0])

    #~~ Gibt die Anzahl y-Raster-Felder (Reihen) zurück
    @property
    def height(self):
        return len(self.dots)

    def __init__(self, width=LCD_WIDTH, height=LCD_HEIGHT):
        """Konstruktor für DotModel"""

        self.dot_gui = None
        self.dots = list()
        self.create_dot_array(width, height)

    def __getitem__(self, coordinates):
        """Lese Rasterfeld-Status"""

        if not self.coord_check(coordinates):
            #~~ Ungültige Koordinate
            return False

        x, y = coordinates
        return self.dots[y][x].state

    def __setitem__(self, coordinates, state):
        """Setze Rasterfeld-Status"""

        if not self.coord_check(coordinates):
            #~~ Ungültige Koordinate
            return False

        x, y = coordinates
        self.dots[y][x].state = state

        if self.dot_gui:
            #~~ Aktualisiere den Zustand des GUI-Rasterfeldes
            self.dot_gui.update_dot_state(coordinates, state)

    def create_dot_array(self, width, height):
        """Erzeuge eine zweidimensionalen Rasterobjekt-Array"""

        temp_row_list = list()
        for  y in xrange(height):
            for x in xrange(width):
                temp_row_list.append(Dot())
            self.dots.append(temp_row_list)
            temp_row_list = list()

    def coord_check(self, coordinates):
        """Raster Koordinaten-Check """

        xcoord, ycoord = coordinates

        if xcoord >= self.LCD_WIDTH:
            #~~ Die x-Koordinate liegt ausserhalb des erlaubten
            #   Raster-Anzeige-Bereiches!
            return False

        if ycoord >= self.LCD_HEIGHT:
            #~~ Die y-Koordinate liegt ausserhalb des erlaubten
            #   Raster-Anzeige-Bereiches!
            return False

        return True

#--- MODUL-TEST --------------------------------------------------------------#
if __name__ == "__main__":

    import os
    import sys
    import Tkinter as tk

    from doglcd_view_01 import*

    #====== Test: Klassen & Funktionen ======#
    def test_open_side_frames():
        """Öffnet versteckte Seiten-Rahmen"""

        for frame_key in app_base.main_view.frame_dict:
            app_base.main_view.frame_control(frame_key)

    def test_open_single_frame(frame_name):
        """Öffnet einen einzelnen Seiten-Rahmen"""

        app_base.main_view.frame_control(frame_name)

    def output_dot_model():
        """Ausgabe des Raster-Models"""

        dot_row = ''
        row_adr = 0
        for y in xrange(app_base.dot_model.height):
            for x in xrange(app_base.dot_model.width):
                if app_base.dot_model.dots[y][x].state:
                    dot_row += '+'
                else:
                    dot_row += '-'
            print "%3.3i " % row_adr + dot_row
            dot_row = ''
            row_adr += 1

    #====== Test: Tk-Hauptfenster ======#
    app_base = tk.Tk()

    #~~ Mache das Hauptfenster unsichtbar
    app_base.withdraw()

    #~~ Haupt-Fenster Titel
    app_base.title(APP_TITLE + " (" + SCRIPT_NAME + ")")

    ##~~ Erstellt die Haupt-Ansicht
    #app_base.main_view = MainView(app_base)

    #~~ Erstellt das Modell
    app_base.dot_model = DotModel()

    app_base.dot_model[16, 4] = True
    print 'State', app_base.dot_model[16, 4]

    output_dot_model()

    #~~ Mache das Hauptfenster sichtbar
    app_base.deiconify()

    app_base.mainloop()
Gruss wuf :wink:
Take it easy Mates!
BlackJack

Na dann… *händereib* :-)

Der Klasse `Dot` könnte man eine `__str__()`-Methode verpassen, die ein '+' oder ein '-' zurück gibt.

`create_dot_array()` ist ziemlich umständlich aufgeschrieben. Die Methode könnte man weglassen und eine kürzere "list comprehension" direkt in die `__init__()` schreiben.

Code: Alles auswählen

    def __init__(self, width=LCD_WIDTH, height=LCD_HEIGHT): 
        """Konstruktor für DotModel""" 

        self.dot_gui = None 
        self.dots = [[Dot() for dummy in xrange(width)]
                     for dummy in xrange(height)]
`__getitem__()` und `__setitem__()` sollten anders auf ungültige Koordinaten reagieren. Was spricht dagegen einfach gar nichts zu prüfen und den `IndexError`, den die Liste im Fehlerfall liefert zu verwenden? Du prüfst übrigens nicht auf negative Koordinaten. Und das `__setitem__()` überhaupt einen Rückgabewert hat, dürfte kaum jemand erwarten, das ist ungewöhnlich.

Und wenn man dem `DotModel` noch eine `__str__()`-Methode verpasst…

Code: Alles auswählen

    def __str__(self):
        result = list()
        for i, row in enumerate(self.dots):
            result.append('%03d %s' % (i, ''.join(map(str, row))))
        return '\n'.join(result)
…kann man sich die `output_dot_model()`-Funktion sparen, die wird dann nämlich zu einem einfachen:

Code: Alles auswählen

    print app_base.dot_model
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo BlackJack

Ich habe deine lehrreichen Hinweise in mein Projekt einfliessen lassen. Hier der modifizierte Code:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Python 2.6
# Skriptname: doglcd_mod_01_04_01.py

class Dot(object):
    """Klasse: Rasterfeld"""

    def __init__(self, state=False):
        """Konstruktor für die Klasse Dot"""

        self.state = state

    def __str__(self):
        """Zustands-Symbol"""

        if self.state:
            return '+'
        else:
            return '-'

class DotModel(object):
    """Klasse: DOGM-LCD-Logic"""

    DOT_SIZE = 10       # Seitenlänge in Pixels
    LCD_WIDTH = 32 #128     # Raster
    LCD_HEIGHT = 8 #64     # Raster

    #~~ Gibt die Anzahl x-Raster-Felder (Spalten) zurück
    @property
    def width(self):
        return len(self.dots[0])

    #~~ Gibt die Anzahl y-Raster-Felder (Reihen) zurück
    @property
    def height(self):
        return len(self.dots)

    def __init__(self, width=LCD_WIDTH, height=LCD_HEIGHT):
        """Konstruktor für DotModel"""

        self.dot_gui = None
        self.dots = [[Dot() for dummy in xrange(width)]
            for dummy in xrange(height)]

    def __str__(self):
        """Test-Ausgabe der Raster-Zustands-Symbole"""

        result = list()
        for i, row in enumerate(self.dots):
            result.append('%03d %s' % (i, ''.join(map(str, row))))
        return '\n'.join(result)

    def __getitem__(self, coordinates):
        """Lese Rasterfeld-Status"""

        x, y = coordinates
        return self.dots[y][x].state

    def __setitem__(self, coordinates, state):
        """Setze Rasterfeld-Status"""

        x, y = coordinates
        self.dots[y][x].state = state

        if self.dot_gui:
            #~~ Aktualisiere den Zustand des GUI-Rasterfeldes
            self.dot_gui.update_dot_state(coordinates, state)

    def create_dot_array(self, width, height):
        """Erzeuge einen zweidimensionalen Rasterobjekt-Array"""

        temp_row_list = list()
        for  y in xrange(height):
            for x in xrange(width):
                temp_row_list.append(Dot())
            self.dots.append(temp_row_list)
            temp_row_list = list()

#--- MODUL-TEST --------------------------------------------------------------#
if __name__ == "__main__":

    import os
    import sys
    import Tkinter as tk

    from doglcd_view_01 import*

    #====== Test: Klassen & Funktionen ======#
    def test_open_side_frames():
        """Öffnet versteckte Seiten-Rahmen"""

        for frame_key in app_base.main_view.frame_dict:
            app_base.main_view.frame_control(frame_key)

    def test_open_single_frame(frame_name):
        """Öffnet einen einzelnen Seiten-Rahmen"""

        app_base.main_view.frame_control(frame_name)


    #====== Test: Tk-Hauptfenster ======#
    app_base = tk.Tk()

    #~~ Mache das Hauptfenster unsichtbar
    app_base.withdraw()

    #~~ Haupt-Fenster Titel
    app_base.title(APP_TITLE + " (" + SCRIPT_NAME + ")")

    ##~~ Erstellt die Haupt-Ansicht
    #app_base.main_view = MainView(app_base)

    #~~ Erstellt das Modell
    app_base.dot_model = DotModel()

    app_base.dot_model[16, 4] = True
    print 'State', app_base.dot_model[16, 4]

    print app_base.dot_model

    #~~ Mache das Hauptfenster sichtbar
    app_base.deiconify()

    app_base.mainloop()
Danke für deine Tipps. Gruss wuf :wink:
Take it easy Mates!
Antworten