Verständnisfrage

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
Torsten2005
User
Beiträge: 34
Registriert: Mittwoch 2. November 2005, 15:37
Wohnort: Berlin
Kontaktdaten:

Hallo , ich weiß nicht so genau , warum die def __str__ in der Klasse Ozoncheck gebraucht wird? Es soll ja nur eine Zahl gefiltert und dann ausgeben werden. Aber ohne diese Methode __str__ gehts nicht ?
Also in self.ergebnis ist doch schon die Zahl (oder objekt) ?
Und die eigentliche Ausgabe ist ja in der 57 Zeile und da wird doch keine __str__ methode aufgerufen ???????

Gruß

Code: Alles auswählen

from httplib import *
from re import *
from Tkinter import *
ausgabe = '''Die Ozonkonzentration der Luft
am Standort %s betr\xe4gt 
%s Mikrogramm pro Kubikmeter
(gemessen in Bodenn\xe4he).'''                        #1

class Ozoncheck:                                      #2
  def __init__ (self, server, pfad, ort):
    try:
      self.ort = ort
      verbindung = HTTPConnection(server)             #3
      verbindung.request('GET', pfad)   
      antwort = verbindung.getresponse()
      self.htmltext = antwort.read()
      verbindung.close()
      self.ergebnis = self.auswerten()
    except:
      self.ergebnis = ''

  def auswerten(self):
     re1 = compile('<tr>.*?' + self.ort + '.*?</tr>') #4
     re2 = compile('\d+</td></tr>')
     re3 = compile('\d+')
     zeile = re1.findall(self.htmltext)[0]
     letztesStueck = re2.findall(zeile)[0]
     return re3.findall(letztesStueck)[0]

  def __str__(self):
      return self.ergebnis

class Benutzungsoberflaeche:
  def __init__(self):
    meinfont = ('Arial', 10)
    self.fenster = Tk()
    self.ort = StringVar()
    self.ergebnis = StringVar()
    self.fenster.title('Ozon-Check')
    self.frame = Frame(self.fenster)
    Label(self.frame, font=meinfont,
          text='Ort: ').pack(side=LEFT)
    Entry(self.frame, font=meinfont,
          textvariable=self.ort).pack(side=LEFT)
    Button(self.frame, font=meinfont, text=' Ozon ',
           command=self.ozoncheck).pack(side=LEFT, padx=5)
    self.frame.pack(padx=5, pady=5)
    Label(self.fenster, font=meinfont,height=4,
          textvariable=self.ergebnis).pack()
    self.fenster.mainloop()

  def ozoncheck(self):                                #5
    zahl = str(Ozoncheck('www.lanuv.nrw.de',
        '/luft/immissionen/aktluftqual/eu_o3_akt.htm',
        self.ort.get()))
    if zahl:
      self.ergebnis.set(ausgabe%(self.ort.get(), zahl))
    else:
	self.ergebnis.set(	'Ihre Anfrage konnte nicht \n bearbeitet werden.') 
      
Benutzungsoberflaeche()
lunar

__str__ liefert eine textuelle Representation eines Objekts, welche zur Ausgabe verwendet werden soll. Im Gegensatz dazu steht __repr__, welche eine möglichst exakte String-Representation zurückgeben soll.
Also in self.ergebnis ist doch schon die Zahl (oder objekt)?
Nein, self.ergebnis ist keine Zahl, sondern ein Objekt vom Typ StringVar, welches den Inhalt eines Labels darstellt. Es ist lediglich die Variable zur Ausgabe, die eigentliche Zahl steht an anderer Stelle.
Und die eigentliche Ausgabe ist ja in der 57 Zeile und da wird doch keine __str__ methode aufgerufen?
Ja, aber du solltest dir vielleicht mal anschauen, was in Zeile 57 genau ausgeben wird: Da wirst du den Namen "zahl" sehen. Nun schau dir mal an, woran dieser in den Zeilen 53 bis 55 gebunden wird. Wie du siehst, wird hier ein Ozencheck-Objekt erzeugt, und an die Funktion str übergeben. str wiederrum ruft die __str__ Methode des Ozencheck Objekts auf.
Torsten2005
User
Beiträge: 34
Registriert: Mittwoch 2. November 2005, 15:37
Wohnort: Berlin
Kontaktdaten:

danke für die schnelle antwort,

? in zeile 53 , wird die variable zahl mit dem string den die klasse ozoncheck mit der methode def auswerten() zurückgibt , belegt . oder?
also dacht ich einfach eine stringumwandlung ? aber scheint wohl nicht so ?
Also man könnte auch schreiben :
zahl=methode(........)
und vorher eine def methode() schreiben die den self.ergebnis-wert zurückgibt?
Eigentlich dachte ich macht das schon die methode auswerten() ??
BlackJack

lunar hat geschrieben:
Also in self.ergebnis ist doch schon die Zahl (oder objekt)?
Nein, self.ergebnis ist keine Zahl, sondern ein Objekt vom Typ StringVar, welches den Inhalt eines Labels darstellt. Es ist lediglich die Variable zur Ausgabe, die eigentliche Zahl steht an anderer Stelle.
Das stimmt so nicht ganz weil ich mal denke, dass Torsten hier das "andere" `self.ergebnis` meinte. In Objekten vom Typ `Ozoncheck` gibt's auch ein Attribut mit dem Namen und das enthält das Ergebnis der Webanfrage als Zeichenkette.

Aus `Ozoncheck` eine Klasse zu machen halte ich für übermässig kompliziert. Das Objekt wird erzeugt, macht eine Webanfrage, das Ergebnis wird abgefragt und dann wird das Objekt auch schon wieder weggeworfen. Es gibt nur zwei Attribute auf dem Objekt, die von den Methoden geteilt werden, dass ist der Ort und das Ergebnis. Den Ort kann man einfach als Argument an `auswerten()` übergeben und das Ergebnis erst am Objekt zwischen zu speichern, statt es sofort per ``return`` zurück zu geben ist wie gesagt, indirekter als es sein müsste.
Torsten2005
User
Beiträge: 34
Registriert: Mittwoch 2. November 2005, 15:37
Wohnort: Berlin
Kontaktdaten:

Den Ort kann man einfach als Argument an `auswerten()` übergeben und das Ergebnis erst am Objekt zwischen zu speichern, statt es sofort per ``return`` zurück zu geben ist wie gesagt, indirekter als es sein müsste.
ja, deswegen , die zahl wird doch schon mit return
"re3.findall(letztesStueck)[0]" zurückgeben. Wieso schreibt man dann noch extra eine methode __str__(self) ??

Also ich muss sozusagen diese __str__() methode schreiben/umänderen damit ich die variable self.ergbnis in die andere Klasse bekomme , oder wie??

Ich frag so bescheuert , weil ich dachté __Str__ (self) liefert schon von hause aus einen String, der das Object repräsentiert?????
BlackJack

Du *musst* gar nichts ändern, es funktioniert ja so.

Wenn man die `__str__()`-Methode nicht selber implementiert, dann wird bei `str(obj)` zwar eine vorgegebene Methode aufgerufen, die eine Zeichenkettendarstellung des Objekts liefert, aber die ist recht nichtssagend:

Code: Alles auswählen

In [1]: class A(object):
   ...:     def __init__(self, a):
   ...:         self.a = a
   ...:

In [2]: x = A(42)

In [3]: str(x)
Out[3]: '<__main__.A object at 0xb787452c>'
Wenn man da etwas anderes haben möchte, dann muss man `__str__()` implementieren, und selbstverständlich dort eine Zeichenkette zurückgeben. Eben die, die man haben möchte.

Code: Alles auswählen

In [4]: class A(object):
   ...:     def __init__(self, a):
   ...:         self.a = a
   ...:     def __str__(self):
   ...:         return '-=> %s <=-' % self.a
   ...:

In [5]: x = A(42)

In [6]: str(x)
Out[6]: '-=> 42 <=-'
Aber wie schon gesagt, finde ich die gesamte Klasse `Ozoncheck` überflüssig. Das kann man auch mit zwei Funktionen lösen:

Code: Alles auswählen

def get_ozonwert(server, pfad, ort):
    verbindung = HTTPConnection(server)
    verbindung.request('GET', pfad)
    antwort = verbindung.getresponse()
    htmltext = antwort.read()
    verbindung.close()
    return auswerten(ort, htmltext)

def auswerten(ort, htmltext):
    re1 = compile('<tr>.*?' + ort + '.*?</tr>')
    re2 = compile('\d+</td></tr>')
    re3 = compile('\d+')
    zeile = re1.findall(htmltext)[0]
    letztesStueck = re2.findall(zeile)[0]
    return re3.findall(letztesStueck)[0]
`get_ozonwert()` liefert das Ergebnis als Rückgabewert.

Beide Funktionen sind allerdings überarbeitenswert. Die Webseite kann man über `urllib2` einfacher herunterladen. Von den regulären Ausdrücken kann man mindestens die letzten beiden zusammenfassen bzw. bei `re2` aus den Ziffern eine Gruppe machen. Und immer mit `findall()` alle vorkommen suchen um dann doch immer nur den ersten Treffer zu nehmen ist komplizierter als `search()` zu verwenden.

Den `ort` sollte man vor dem Einsetzen in den regulären Ausdruck übrigens mit `re.escape()` behandeln, sonst gibt's unangenehme Überraschungen, wenn da mal Zeichen mit besonderer Bedeutung in Bezug auf reguläre Ausdrücke im Ortsnamen sind.
Torsten2005
User
Beiträge: 34
Registriert: Mittwoch 2. November 2005, 15:37
Wohnort: Berlin
Kontaktdaten:

aha , danke.
Antworten