besser so oder so?

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.
Gast

besser so oder so?

Beitragvon Gast » Samstag 17. April 2004, 11:37

hallo zusammen!

ich habe ne weile überlegt, in welcher rubrik ich posten soll, da es aber eigentlich um oop geht bin ich hoffentlich hier richtig.

es handelt sich um ein bzw. zwei module. beide stellen bei bedarf dynamisch generierte webseiten zur verfügung. abgesehen von dem unterschied, den ich dann noch diskutieren möchte, unterscheiden sich darin, dass die neuere fassung konsequent auf english bei namen setzt.

das modul ist eigentlich schon sehr gross, habe es aber gekürzt, mehr als folgender code ist für die besprechung wohl nicht notwendig.

beide versionen funktionieren. es scheint mir aber, dass die neuere fassung mehr dem entspricht, was man bez. oop vermittelt bekommt. ob das wirklich so ist, und welche vorteile damit langfristig verbunden sind, ist mir nicht klar. oder ist eine quasie rein ästethische angelegen heit?

zuerst die alte fassung:

Code: Alles auswählen

#!/usr/local/bin/python


from webtools import*



class Seite:

    def __init__(self):
        self.typ='''Content-Type: text/html

        '''
       
        self.allgemein='''<html><head><title>crossoverguitar</title>
        <link rel='stylesheet' type='text/css' href='../../crossover/sheet1.css'></head>
        <body background='../../crossover/_themes/kopie-von-sumi-malerei/sumtextb.jpg'
        link='#000000' vlink='#666699' alink='#990099'>
        <div align='center'>'''
        self.divb='''<div style='width:555; margin-top:150px; margin-bottom:125px;'>'''
       
        self.inhalt='''<h2 style='font-family:Arial, Helvetica'>Eine dynamisch erstellte Seite</h2>
        <p><a href='http://localhost/crossover/'>...zur&ck zu Crossoverguitar</a></p>'''

        self.ende='''</div></div><p><br><hr color='#990000'>
        <div align='center'>
        <span style='font-size:10pt'>©right 2000 roga-verlag ---
        <a href='mailto:rolandgall@weberanto.net' target='inhalt'>rolandgall@weberanto.net</a>
        </span></div></p></body></html>'''
             
    def __str__(self):
        seite=self.typ+self.allgemein+self.divb+self.inhalt+self.ende
        return seite




class FehlerSeite(Seite):

    def __init__(self,fehlertyp,link):
        Seite.__init__(self)
         
        self.fehlertyp=fehlertyp
        self.link=link
        self.inhalt='''<h2 style='font-family:Arial, Helvetica'>%s</h2>
        <p><a href='javascript:history.back()'>zur&ck %s</a></p>'''%(self.fehlertyp,self.link)
       



class BestaetigungsSeite(Seite):

    def __init__(self,bestaetigung):
        Seite.__init__(self)

        self.bestaetigung=bestaetigung
        self.inhalt='''<h2 style='font-family:Arial, Helvetica'>%s</h2>'''%(self.bestaetigung)



die neue fassung, hier wird also das was sowieso immer gleich ist als klassenvariablen definiert und nicht im konstruktor festgelegt:

Code: Alles auswählen

#!/usr/local/bin/python

from webtools import *



class Site:

    type='''Content-Type: text/html

    '''

    general='''<html><head><title>crossoverguitar</title>
    <link rel='stylesheet' type='text/css' href='../../crossover/sheet1.css'></head>
    <body background='../../crossover/_themes/kopie-von-sumi-malerei/sumtextb.jpg'
    link='#000000' vlink='#666699' alink='#990099'>
    <div align='center'>'''

    end='''</div></div><p><br><hr color='#990000'>
    <div align='center'>
    <span style='font-size:10pt'>©right 2000 roga-verlag ---
    <a href='mailto:rolandgall@weberanto.net' target='inhalt'>rolandgall@weberanto.net</a>
    </span></div></p></body></html>'''


   
    def __init__(self):

        self.divb='''<div style='width:555; margin-top:150px; margin-bottom:125px;'>'''
       
        self.content='''<h2 style='font-family:Arial, Helvetica'>Eine dynamisch erstellte Seite</h2>
        <p><a href='http://localhost/crossover/'>...zur&ck zu Crossoverguitar</a></p>'''

       
    def __str__(self):
        site=self.type+self.general+self.divb+self.content+self.end
        return site   




class ErrorSite(Site):

    def __init__(self,errortype,link):
        Site.__init__(self)
         
        self.errortype=errortype
        self.link=link
        self.content='''<h2 style='font-family:Arial, Helvetica'>%s</h2>
        <p><a href='javascript:history.back()'>zur&ck %s</a></p>'''%(self.errortype,self.link)
       



class ConfirmationSite(Site):

    def __init__(self,confirmation):
        Site.__init__(self)

        self.confirmation=confirmation
        self.content='''<h2 style='font-family:Arial, Helvetica'>%s</h2>'''%(self.confirmation)



bedanke mich schon im voraus für eure anregungen, erklärungen und kritiken

mfg

rolgal
Gast

Beitragvon Gast » Samstag 17. April 2004, 11:46

nochmal ich:

ich glaube, wenn man die neue fassung konsequent macht, dann muesste wohl die aenderung erfolgen:

Code: Alles auswählen

#!/usr/local/bin/python

from webtools import *



class Site:

    type='''Content-Type: text/html

    '''

    general='''<html><head><title>crossoverguitar</title>
    <link rel='stylesheet' type='text/css' href='../../crossover/sheet1.css'></head>
    <body background='../../crossover/_themes/kopie-von-sumi-malerei/sumtextb.jpg'
    link='#000000' vlink='#666699' alink='#990099'>
    <div align='center'>'''

    end='''</div></div><p><br><hr color='#990000'>
    <div align='center'>
    <span style='font-size:10pt'>©right 2000 roga-verlag ---
    <a href='mailto:rolandgall@weberanto.net' target='inhalt'>rolandgall@weberanto.net</a>
    </span></div></p></body></html>'''


    divb='''<div style='width:555; margin-top:150px; margin-bottom:125px;'>'''
   
   
    def __init__(self):
       
       
        self.content='''<h2 style='font-family:Arial, Helvetica'>Eine dynamisch erstellte Seite</h2>
        <p><a href='http://localhost/crossover/'>...zur&ck zu Crossoverguitar</a></p>'''

       
    def __str__(self):
        site=self.type+self.general+self.divb+self.content+self.end
        return site   




class ErrorSite(Site):

    def __init__(self,errortype,link):
        Site.__init__(self)
         
        self.errortype=errortype
        self.link=link
        self.content='''<h2 style='font-family:Arial, Helvetica'>%s</h2>
        <p><a href='javascript:history.back()'>zur&ck %s</a></p>'''%(self.errortype,self.link)
       



class ConfirmationSite(Site):

    divb='''<div style='width:555; margin-top:100px; margin-bottom:125px;'>'''

    def __init__(self,confirmation):
        Site.__init__(self)

        self.confirmation=confirmation
        self.content='''<h2 style='font-family:Arial, Helvetica'>%s</h2>'''%(self.confirmation)


im falle einer aenderung, wie sie porbehalber hier mit divb gemacht wird, muss es auch dann in seiner form als klassenvariable ueberschrieben, werden.

mfg

rolgal
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Samstag 17. April 2004, 12:51

Hi rolgal,

die letzte Fassung ist ja schon recht schön, allerdings würde ich die stylesheets konsequenter einsetzen und auch den % Operator für Strings.

Ich bastel mal eine Site-Klasse und poste sie dann.


Gruß

Dookie
Gast

Beitragvon Gast » Samstag 17. April 2004, 13:08

hi dookie!

freut mich, dass dir der ansatz gefällt, details gibt es sicher viele, die zu verbessern sind, bin schon gespannt auf deinen code!

ich kann aber noch nicht verstehen, was an der letzten fassung tatsächlich besser ist, als in der ersten.

geht es da nur um design? warum würdest du diese variablen im konstruktor nicht festlegen, sondern sie als klassenvariablen definieren?


mfg

rolgal
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Samstag 17. April 2004, 14:15

Hi rolgal,

ersmal mein erster Entwurf.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
    Modul:          Site
    Description:    Beschreibung
    Version:        V0.1
    Copyright:      2003 by Fritz Cizmarov fritz(at)sol.at
    Created:        17. Apr. 2004
    Last modified:  17. Apr. 2004
    License:        free
    Requirements:   Python2.3
    Exports:        Classes and Functions to export
"""

site_template = """<html>
  <head>
    <title>%(title)s</title>
    <link rel="stylesheet" type="text/css" href="%(stylesheet)s"/>
  </head>
  <body>
    %(header)s
    <div align="center">
      %(content)s
    </div>
    %(footer)s
  </body>
<html>"""

site_header = ""

site_footer = """<div align="center"><span class="copyright">
      <a href="mailto:%(master_mail)s" target="inhalt">%(master_mail)s</a>
    </span></div>"""


class Site(object):
    __slots__ = ["site_vars"]
   
    base_vars = {"site"        : site_template,
                 "title"       : "crossoverguitar",
                 "stylesheet"  : "../../crossover/sheet1.css",
                 "header"      : site_header,
                 "content"     : "",
                 "master_mail" : "rolandgall@weberanto.net",
                 "footer"      : site_footer}

    content_type = "Content-Type: text/html\n\n"
   
    def __init__(self, **kw):
        self.site_vars = self.base_vars.copy() # grundeinstellungen
        self.site_vars.update(kw) # übergebene Variablen einfügen

    def __str__(self):
        site = self.site_vars["site"] % self.site_vars
        return self.content_type + site % self.site_vars

if __name__ == "__main__":
    s = Site(content="Hallo Welt")
    print s


Klassenvariablen haben ein paar Vorteile. Sie werden nur in der Klasse definiert, Instanzvariablen aber für jede Instanz einer Klasse, so hast Du sehr viel Renundanz wenn du auf Klassenvariablen verzichtest.
Auch wenn Du Klassen von Klassen mit Klassenvariablen ableitest, brauchst Du nur geänderte oder neue Klassenvariablen neu definieren und musst dich nicht mehr in der __init__ Methode darum kümmern.

Ich habe sogar die Templates aus der Klasse rausgenommen, so ist das ganze besser lesbar und wird auch noch bei der Ausgabe schön formatiert.

Die HTML-Formatierung wird bei meinem Beispiel dann ganz dem CSS überlassen. Also keine Farben Hintergründe, Schriften und Stiele werden im HTML direkt angegeben sondern in CSS-Klassen definiert.


Gruß

Dookie
Gast

Beitragvon Gast » Samstag 17. April 2004, 14:25

woooooooooooow! ich werde mal versuchen, das zu verstehen,

weisst du was mir noch net ganz klar ist:

warum diese angabe?

Code: Alles auswählen

#!/usr/bin/env python


wollte ich dich schon bei unserer letzten besprechung fragen, bez. upload. ich habe schon gemerkt, dass der upload z.b. net funzt bei

Code: Alles auswählen

#/usr/local/bin/python
aber warum genau, also im detail ist mir das net klar.

das mit den klassenvariablen ist mir jetzt auch klarer, glaube ich mal :D

mfg

rolgal
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Samstag 17. April 2004, 15:03

Code: Alles auswählen

#!/usr/bin/env python
und die anderen Kommentarzeilen am Anfang macht mein VIM automatisch wenn ich ein neues Pythonscript editiere ;)

Mit /usr/bin/env werden sicher alle definierten Umgebungsvariablen an Python mit übergeben, dort können dann auch noch explizit Umgebungsvariablen definiert oder gelöscht werden, siehe man env


Gruß

Dookie
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Samstag 17. April 2004, 17:31

Hi rolgal,

hier mal ein Beispiel, wie man von Site eine Klasse für Fehlerseiten ableiten könnte:

Code: Alles auswählen

class ErrorSite(Site):
    __slots__ = [] # wir brauchen keine neuen Attribute!
    base_vars = Site.base_vars.copy()
    base_vars["title"] = "cog-error"
    base_vars["header"] = "<h2>Fehler %(error_num)s</h2>"
    base_vars["error_num"] = "4711"
    base_vars["content"] = "<b>%(error_msg)s</b>"
    base_vars["error_msg"] = "Echt k&lnisch Wasser!"

wichtig ist, daß erst eine Kopie von den base_vars von Site erstellt wird, würden wir Site.base_vars direkt manipulieren, würde sich das auch auf die Basisklasse und andere davon abgeleitete Klassen auswirken, so wird für die ErrorSite ein eigenes base_vars Dictionary angelegt.

Am Ende des Scripts kannst Du dann folgende Zeilen anfügen.

Code: Alles auswählen

    e = ErrorSite(error_num="404", error_msg="Seite nicht gefunden!")
    print e


Gruß

Dookie
Gast

Beitragvon Gast » Sonntag 18. April 2004, 12:16

hi dookie!

das war wirklich beeindruckend und ich werde mit diesen new style klassen auch gleich experementieren. für ein fertiges oder weit fortgeschrittenes projekt, will ich aber code verwenden, den ich zu 100% verstehe oder glaube zu verstehen :D

ich habe nochmal meine version versucht zu verbessern, wollte mal wissen, wie du das siehst:

Code: Alles auswählen

#!/usr/local/bin/python


from webtools import *




class Site:

    type='''Content-Type: text/html

    '''

    general='''<html><head><title>crossoverguitar</title>
    <link rel='stylesheet' type='text/css' href='../../crossover/sheet1.css'></head>
    <body background='../../crossover/_themes/kopie-von-sumi-malerei/sumtextb.jpg'
    link='#000000' vlink='#666699' alink='#990099'>
    <div align='center'>'''

    end='''</div></div><p><br><hr color='#990000'>
    <div align='center'>
    <span style='font-size:10pt'>©right 2000 roga-verlag ---
    <a href='mailto:rolandgall@weberanto.net' target='inhalt'>rolandgall@weberanto.net</a>
    </span></div></p></body></html>'''


    divb='''<div style='width:555; margin-top:150px; margin-bottom:125px;'>'''

    content='''<h2 style='font-family:Arial, Helvetica'>Eine dynamisch erstellte Seite</h2>
    <p><a href='http://localhost/crossover/'>...zur&ck zu Crossoverguitar</a></p>'''
   
       
    def __str__(self):
        site=self.type+self.general+self.divb+self.content+self.end
        return site   




class ErrorSite(Site):

    content='''<h2 style='font-family:Arial, Helvetica'>%s</h2>
    <p><a href='javascript:history.back()'>%s</a></p>'''

    def __init__(self,errortype,link):
         
        self.errortype=errortype
        self.link=link
        self.content=self.content%(self.errortype,self.link)
       
       


class ConfirmationSite(Site):

    divb='''<div style='width:555; margin-top:100px; margin-bottom:125px;'>'''
    content='''<h2 style='font-family:Arial, Helvetica'>%s</h2>'''

    def __init__(self,confirmation):

        self.confirmation=confirmation
        self.content=self.content%(self.confirmation)



mir scheint das noch etwas konsequenter zu sein, denn angefangen hat ja alles mit der idee alles was gleich bleibt als klassenvariablen zu definieren und im konstruktor eigentlich nur änderungen zuweisen usw.

die basisklasse braucht somit keinen konstruktor.

mfg

rolgal

mfg rolgal
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Sonntag 18. April 2004, 12:45

Hi rolgal,

ich hab da einen anderen Ansatz, für mich sollte die Basisklasse so allgemein und intelligent wie möglich sein, damit ich in abgeleiteten Klassen nur noch die Teile ergänzen muss, die wirklich neu sind bzw deren Verhalten sich ändern soll. Selbst abstrakte Basisklassen bekommen eine __init__ Methode und rufen dann oft abstrakte (funktionslose) Methoden auf, die erst in abgeleiteten Klassen redefiniert werden.

Das hat IMHO auch den Vorteil, wenn in der Basisklasse etwas optimiert wird, so profitieren alle abgeleiteten Klassen davon. Bei Deinem Entwurf, muss dann jede abgeleitete Klasse geändert werden und wehe du vergisst das bei einer abgeleiteten Klasse.

Noch ein Nachteil Deiner Version ist, daß der HTML-Code der erzeugt wird nur schlecht zu lesen ist. Um beides besser lesbar zu machen, habe ich die HTML-Gerüste als normale Textvariablen definiert, in einem Webprojekt würde ich diese warscheinlich sogar als extra Textdateien definieren die dann in der Klassendefinition in Klassenvariablen eingelesen werden.

Code: Alles auswählen

class Site(object):
    __slots__ = ["site_vars"]
    content_type = "Content-Type: text/html\n\n"
    template = file("site.tpl", 'r').read()
    ...


Du hast in Deiner Basisklassen den content-type type genannt, was IMHO keine so gute Idee ist, da type ja eigentlich eine eingebaute Funktion ist die Du dadurch in der Klassendefinition nicht mehr verwenden kannst. Das solltest Du doch in content_type ändern. Und da siehste schon, wo du jetzt ein Problem hast, du musst dann auch alle abgeleiteten Klassen ändern.


Gruß

Dookie
Gast

Beitragvon Gast » Sonntag 18. April 2004, 12:54

hi dookie!

...bin schon wieder beim optimieren. die stylesheets lager ich grad mal alle aus.

ich kann da nicht folgen:

Das solltest Du doch in content_type ändern. Und da siehste schon, wo du jetzt ein Problem hast, du musst dann auch alle abgeleiteten Klassen ändern.


habe ich gemacht, aber die klassenvariablen werden ja vererbt. also wenn type jetzt content-type heisst, muss ich mich doch um nichts kümmern. oder was hast du gemeint?

mfg

rolgal
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Sonntag 18. April 2004, 13:17

Hi rolgal,

das habe ich so gemeint, daß du alle Klassen durchsehen musst, ob du wo self.type verwendest oder neu zuweist. Könnte ja sein, daß du irgendwo bei einer Seite xhtml oder xml verwenden willst statt html.


Gruß

Dookie
Gast

Beitragvon Gast » Sonntag 18. April 2004, 18:43

hallo dookie


ich hirne, hirne und hirne....aber es bleibt mir einiges noch unklar:

mal das zuerst:

Code: Alles auswählen

site_template = """<html>
  <head>
    <title>%(title)s</title>
    <link rel="stylesheet" type="text/css" href="%(stylesheet)s"/>
  </head>
  <body>
    %(header)s
    <div align="center">
      %(content)s
    </div>
    %(footer)s
  </body>
<html>"""


Code: Alles auswählen

    base_vars = {"site"        : site_template,
                 "title"       : "crossoverguitar",
                 "stylesheet"  : "../../crossover/sheet1.css",
                 "header"      : site_header,
                 "content"     : "",
                 "master_mail" : "rolandgall@weberanto.net",
                 "footer"      : site_footer}


so, die werte in der var

Code: Alles auswählen

site_template
kommen wohl von dem dictionary

Code: Alles auswählen

base_vars


doch wie kann das sein, der interpreter arbeitet ja von oben nach unten durch, wenn er

Code: Alles auswählen

site_template
liest müsster er doch aussteigen, weil zu dem zeitpunkt die werte aus dem dictionary noch unbekannt sind.
ausserdem verwendest du da eine interessante schreibweise für die stringoperatoren, hast du ein ganz einfaches bsp, ich wollte das nachbilden, ging aber nicht.

also meine frage, warum funktioniert das überhaupt?

mfg

rolgal
Benutzeravatar
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Beitragvon Dookie » Sonntag 18. April 2004, 19:39

Hi rolgal,

mit der Schreibweise "%(name)s" können Werte aus einem Dictionary in einen String mit dem %-Operator eingefügt werden, diese können auch mehrfach verwendet werden. Sind in dem Dictionary mehr Werte als im String verwendet werden so macht das nichts, nur wenn auf Werte zugegriffen werden soll, die nicht im Dictionary enthalten sind, gibts eine Fehlermeldung.
Ohne %-Operator hinter dem String, werden Formatierungsanweisungen mit dem "%" im String nicht beachtet und als ganz normale Zeichen angesehen.

hier mal ein einfaches Beispiel:

Code: Alles auswählen

my_string = """Es macht spass mit %(sprache)s zu Programmieren,
darum verwendet %(name)s so gerne %(sprache)s."""

print my_string # my_string ist einfach nur ein String mit % darin

my_dict = {"name":"Dookie", "sprache":"Python", "unsinn":"wird nicht benötigt, stört aber auch nicht"}

# hier werden erst die Daten aus my_dict in den String eingefügt mittels %-Operator
print my_string % my_dict


Das ganze funktioniert in meinem Beispiel, weil an der Stelle noch keine Daten in den String eingefügt werden. Du kannst ja Testweise mal nach der Zuweisung base_vars = ... ein print base_vars["site"] machen und schaun was da ausgegeben wird, einfach der String mitsamt den Formatierungsanweisugngen %(irgendwas)s.
Die Daten aus self.site_vars werden erst wenn die Methode __str__(self) aufgerufen wird mit dem String self.site_vars["site"] zusammengetragen.

Ich habe hier die Methode __str__(self) nochmal etwas "gesprächiger" gemacht, das ganze ist doch etwas Trickreich ;)

Code: Alles auswählen

    def __str__(self):
        site = self.site_vars["site"] % self.site_vars
        print site
        result = self.content_type + site % self.site_vars
        print result
        return result

erst wird in der Variablen site der String in self.site_vars["site"] mit Daten aus dem Dictionary self.site_vars gefüllt. Hier gibts in self.site_vars["footer"] wieder einen String mit %-Formatierugen. Der String wird mitsamt den Formatierungen zum einfügen von z.B. deiner Emailadresse "%(master_mail)s" in den String eingefügt dieses aber nicht ersetzt.
Bei result = self.content_type + site % self.site_vars wird der Eintrag aus self.site_vars["master_mail"] in den String eingeflochten und an result der string "self.content_type" plus dem fertig formatierte String übergeben, der jetzt auch Deine Emailaddy enthält.


Gruß

Dookie
Gast

Beitragvon Gast » Dienstag 20. April 2004, 11:19

hi dookie!

also weitestgehend kann ich jetzt folgen,....frage ist, ist es sinnvoll einen footer, der immer gleich ist seperat zu definieren, betrifft dann auch den header eventuell?

mfg

rolgal

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder