Klassenattribute (static & dynamic)

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
maxwell
User
Beiträge: 69
Registriert: Samstag 11. Juli 2009, 15:36
Wohnort: am Fernsehturm in B.

Hallo Freunde,

ich habe folgende Verständnisfrage. Hintergrund ist ein kleines Projekt, dass ich bereits mit Hilfe eines UML-Designers erstellt habe. Bei der Code-Generierung ist mir dann aufgefallen, dass Attribute grundsätzlich im Klassenkopf definiert werden. Das liegt am Designer soweit schon klar, nur forschte ich ein wenig nach und bin hinsichtlich der Art der Attributdefinition zu keinem verständlichen Ergebnis gekommen.

Wenn ich das richtig verstanden habe, dann gelten die im Klassenkopf definierten Attribute als statisch?

Code: Alles auswählen

 
class a(object):
    stat = 0
    def __init__(self): pass
Ich kann also mit a.stat auf das Attribut zugreifen. Ausgabe wäre ja hier 0.
Wenn ich jetzt noch folgendes Anfüge:

Code: Alles auswählen

class a(object):
    stat = 0
    def __init__(self):
        self.stat+=1
Wird dann "stat" überschrieben? Ich habe ja der Klasse jetzt einen dynamischen Member verpasst.

Hinsichtlich des Designers muss ich mir jetzt gedanken machen. Denn ich möchte in meinem UML-Diagramm schon die Attribute sehen die ich auch definiert habe. Aber sobald ich diese definiere packt er sie mir in den Klassenkopf. Lasse ich die Attribute weg, geht mir ein Teil der Logik im UML-Diagramm verloren.

Wie handhabt ihr denn so etwas?

Viele Grüße und vielen Dank im voraus.

Chris
be or not to be
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Statisch und dynamisch passt nicht. ``stat`` ist einmal Klassen- und einmal Instanzattribut.
Warum der Code ueberhaupt funktioniert liegt an den Lookupregeln: Es wird zuerst der Instanz- und dann der Klassennamensraum durchsucht.

UML ist fuer statische Sprachen entworfen, mit Python hast du eher Probleme wenn du die Konzepte 1:1 uebernimmst und auch noch Code generieren laesst.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Code: Alles auswählen

>>> class A(object):
...   stat = 0
...   def count(): self.stat += 1
... 
>>> a = A()
>>> A.stat
0
>>> a.count()
>>> a.stat
1
>>> A.stat
0
Vorsicht: In dem Fall legst du dir eine neue Instatnzvariable an mit dem gleichen Namen. Erst liest du stat, bei lesendem Zugriff wird automatisch in dem hoehergelegenen Namensraum gesucht, in diesem Fall also die Klassenvariable stat genommen, beim anschliessenden Schreibzugriff wird dann die neue Instanzvariable angelegt.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
maxwell
User
Beiträge: 69
Registriert: Samstag 11. Juli 2009, 15:36
Wohnort: am Fernsehturm in B.

Hallo und erstmal vielen Dank für eure Erleuterungen.

@ cofi
Klassen- und einmal Instanzattribut
Ok, ich habe verstanden, das war jetzt einleuchtend.

@ Rebecca, cofi

Ich habe jetzt das Template des UML-Designers angepasst. Es wird immer automatisch ein Implementor angelegt sofern dieser nicht definiert wurde. Sobald das Attribute nicht const oder static ist, wird es über den Implementor ´__init__()´ hinzugefügt. Ich denke so geht mir nicht die Logik verloren.

@ cofi
UML ist fuer statische Sprachen entworfen, mit Python hast du eher Probleme wenn du die Konzepte 1:1 uebernimmst und auch noch Code generieren laesst.
Wie sollen dann große Projekte abgehandelt werden. Ich meine es ist doch eine super Bereicherung wenn ich das Projekt modelltechnisch entwerfe. Abgesehen von der Doku die daraus auch noch ableiten kann.

Viele Grüße

Chris
be or not to be
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Du kannst UML natuerlich benutzen, aber es gibt eben viele dieser Konzepte nicht in Python bzw Python hat zusaetzliche Konzepte.
Du machst mit ``const`` und ``static`` in der Dokumentation Versprechungungen, die der Code nicht halten kann. Deshalb kann ich mich mit UML - wegen der starken Ausrichtung auf Java/C++ - fuer Python abseits der Klassenhierarchien und Flowcharts nicht erwaermen.
maxwell
User
Beiträge: 69
Registriert: Samstag 11. Juli 2009, 15:36
Wohnort: am Fernsehturm in B.

Ich habe auch meine Bauchschmerzen damit, weil es eben nicht optimal ist. Mit optimal meine ich, dass es - so wie Du schon sagtest - zu Missverständnissen kommen könnte. Andererseits möchte ich aber auch, dass bei steigender Komplexität die Übersicht nicht verloren geht.

Vielleicht fällt mir ja noch was ein. Der Designer ist auf alle Fälle super flexibel.

Viele Grüße,

Chris
be or not to be
lunar

UML ist beim Entwurf größer Python-Programme meiner Meinung nach eher hinderlich als nützlich. Durch die Verwendung von Klassendiagrammen schränkst Du Dich auf die UML-Auffassung von Klassen ein, die in mancherlei Hinsicht unzureichend ist.

So kennen Klassendiagramme nur Typen, aber keine Protokolle. Würde man ein Klassendiagramm der Python-Standardbibliothek erstellen, so stünden "StringIO" und "file" in diesem Diagramm in keiner unmittelbaren Beziehung, obwohl beide Klassen das selbe Protokoll eines "file-like object" implementieren. Nahezu jede Python-Methode, die ein "file"-Objekt entgegen nimmt, funktioniert auch mit einem StringIO-Objekt. Dieser wesentliche Aspekt der dynamischen Typisierung fällt bei UML völlig unter den Tisch.

Ebenso kennen Klassendiagramme keine Funktionen. Ein aus einem Klassendiagramm abgeleiteter Entwurf enthält niemals Funktionen, Generatoren, usw, obwohl man Datenströme sehr schön mit verschachtelten Generatoren und Funktionen implementieren kann.

Ich persönlich sehe daher keinen Vorteil in detaillierten Klassenmodellen für Python-Code. Klassenhierarchien werden selten so komplex wie in Java, eben weil Python mit Protokollen und Funktionen mächtigere und ausdrucksstärkere Konzepte bietet. Zudem verzichtet die Syntax von Python auf allerlei Boilerplate-Konstrukte. Code-Generierung bietet also keinen nennenswerten Vorteil. Dafür aber muss man das Modell mit der Implementierung konsistent halten, was letztendlich wahrscheinlich mehr Zeit in Anspruch nimmt als man durch Code-Generierung spart.

Den Vorteil einer Dokumentation sehe ich auch nicht wirklich. Freitext- und API-Dokumentation, die Klassen, Methoden und Funktionen beschreibt, muss man so oder so eh noch schreiben. Wenn diese gut geschrieben ist, dann gibt sie fast schon automatisch auch eine gute Übersicht über das Projekt. Ein Klassendiagramm liefert daher keine Erkenntnisse, die nicht auch aus solch "klassischer" Dokumentation zu entnehmen wäre, zumal Klassendiagramme schon bei verhältnismäßig kleinen Programmen schnell sehr unübersichtlich werden. Wenn schon Diagramme, dann eher Aktivitäts- oder Zustandsdiagramme, die tatsächlich verwertbare Informationen liefern, die aus API- oder Freitext-Doku nicht unmittelbar ersichtlich sind.

Aber wenn schon UML, dann bitte nur bis zur Architekturebene, aber nicht auf Klassenebene. Ansonsten verbaust Du Dir durch die Fokussierung auf UML viele, elegantere und schnellere Lösungsansätze für Probleme.
maxwell
User
Beiträge: 69
Registriert: Samstag 11. Juli 2009, 15:36
Wohnort: am Fernsehturm in B.

hallo lunar,

erstmal danke für Deine ausführliche Antwort.

Vorab: Ich gebe Dir in Teilen recht solange es nicht um eine sehr tiefe Sicht geht. Dennoch bin ich mit folgendem nicht so einverstanden.

Was meinst du mit Protokolle genau?
Ebenso kennen Klassendiagramme keine Funktionen.
Bevor ich meinen Senf dazu gebe, kannst Du diese Aussage genauer machen?
Ein aus einem Klassendiagramm abgeleiteter Entwurf enthält niemals Funktionen, Generatoren, usw
Sagst Du das? Wenn ich Dich richtig verstanden habe, dann meinst Du das konkrete implementieren der Funktionsrümpfe aus einer in UML beschriebenen Klasse?
Zudem verzichtet die Syntax von Python auf allerlei Boilerplate-Konstrukte
Was ist mit importen? Ist das kein boilerplate-code? Die können u.U. ähnlich Aufwendig sein. Zumal mit unter auch Rückwärtkompatibilität eine Rolle spielt. ´Queue´ (PyVersion 2.7) vs. ´queue´ (PyVersion 3.0) und anschließendem try/except.
Dafür aber muss man das Modell mit der Implementierung konsistent halten
Das ist nicht nur in Python so.
Freitext- und API-Dokumentation, die Klassen, Methoden und Funktionen beschreibt, muss man so oder so eh noch schreiben
Nein ist bereits durch das Modell und durch die in dem Modell hinterlegten Notes passiert. Einfach Button ´generate doc´ und fertig.


Viele Grüße

Chris
be or not to be
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

maxwell hat geschrieben:Was meinst du mit Protokolle genau?
Sowas wie Interfaces nur eben ohne formale Spezifizierung. Wie das engesprochende file-like-object, das eine ``.write()``-Methode enthalten muss, damit es dem Protokoll entspricht. Antere Protokolle wären etwa das Sequence-Protokoll (list, tuple), das Number-Protokoll (int, float), Mapping-Protokoll (dict), Iterator-Protokoll. Ansonsten kann man noch das Context-Manager-Protokoll nennen (durch die Methoden ``__enter__`` und ``__exit__`` zu erkennen). Es geht quasi um ein Verhalten das ein Objekt bietet: wenn das objekt quakt, ist es eine Ente. Es muss nicht das IQuackendesVogelvieh-Interface implementieren um als Ente erkannt zu werden.
maxwell hat geschrieben:
Ebenso kennen Klassendiagramme keine Funktionen.
Bevor ich meinen Senf dazu gebe, kannst Du diese Aussage genauer machen?
Nunja, Java kennt keine Methoden die nicht zu Klassen gehören, also muss alles was besser in einer Funktion aufgehoben wäre unnötigerweise in Klassen gesteckt werden. UML kennt auch keine Funktionen, ebenfalls nur methoden:

Zur Illustration:

Code: Alles auswählen

def add(a, b):
    return a + b

result = add(3, 4)
vs.

Code: Alles auswählen

class Adder(object):
    def add(self, a, b):
        return a + b

result = Adder().add(3, 4)
Steve Yegge schreibt viel wenn der Tag lang ist, aber sein Kingdom of Nouns ist IMHO eine gelungene Lektüre zu dem Thema.
maxwell hat geschrieben:
Ein aus einem Klassendiagramm abgeleiteter Entwurf enthält niemals Funktionen, Generatoren, usw
Sagst Du das? Wenn ich Dich richtig verstanden habe, dann meinst Du das konkrete implementieren der Funktionsrümpfe aus einer in UML beschriebenen Klasse?
Lunar will damit aussagen, dass UML-Klassendiagramme zu beschränkt sind, einige nützliche Konzepte aus Python darzustellen, etwa eben Funktionen oder Funktionen deren Ausführung gestoppt werden kann und später wieder aufgenommen werden kann (Generatoren).
maxwell hat geschrieben:
Zudem verzichtet die Syntax von Python auf allerlei Boilerplate-Konstrukte
Was ist mit importen? Ist das kein boilerplate-code? Die können u.U. ähnlich Aufwendig sein. Zumal mit unter auch Rückwärtkompatibilität eine Rolle spielt. ´Queue´ (PyVersion 2.7) vs. ´queue´ (PyVersion 3.0) und anschließendem try/except.
Nein. Wenn ich mich richtig erinnere ist in Java der ganze Classpath geladen und die ``import``-Statements sind nur defür da, dass man eine Referenz auf die Klassen bekommt. In Python werden bei einem Import die Module erst geladen, d.h. zur Laufzeit des Programmes und nicht zur Compilezeit. Somit machen die ``import`` Statements in Python wirklich etwas wesentliches und man kann nicht einfach auf sie verzichten. Boilerplate ist ja üblicherweise solcher Code der geschrieben wird, aber keinen weiteren Nutzen bringt (bzw. man hätte den Nutzen gerne als Standardverhalten, statt als Option). Das Erben von ``object`` in Python 2.x könnte als Boilerplate durchgehen, praktischerweise ist das in Python 3.x das Standardverhalten geworden.

Achja, 2to3 existiert, also musst du nicht zwischen queue und Queue unterscheiden.
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:

Versuche das mal in UML zu modellieren:

Code: Alles auswählen

def foo():
    pass
;-)
lunar

Ein Protokoll definiert ein Verhalten. Da Python nicht statisch typisiert ist, und in der Regel auf Typprüfungen verzichtet wird, kann man beliebige Typen übergeben, solange sie sich nur so verhalten, wie vom aufgerufenen Objekt erwartet wird. Beziehungen zwischen Objekten, die nur darin bestehen, dass sich diese Objekte gleich verhalten ohne aber gleichen Typs zu sein, lassen sich mit UML nicht abbilden. Das betrifft beispielsweise die genannten Klassen "file" und "StringIO" oder beispielsweise aber "lxml.etree.Element" und "xml.etree.ElementTree.Element".

Klassen haben im Übrigen keine Funktionen, Klassen haben Methoden. UML modelliert nur Klassen und Methoden, aber keine freistehenden Funktionen wie beispielsweise "open()" oder "itertools.chain()". Solche Funktionen tauchen in einem Klassenentwurf niemals auf und damit fallen ganze Konzepte unter den Tisch (z.B. das Modellieren von Datenströmen als Verkettung von Generatorfunktionen).

Natürlich muss man auch in anderen Sprachen Modell und Implementierung konsistent halten. Allerdings ist das in Java-ähnlichen Sprachen ungleich einfacher, weil man das Modell größtenteils auch wieder aus dem Code ableiten kann. Mit Python funktioniert das nicht so gut, weil Python ausdrucksstärker ist als UML und man Python-Code auch nicht in dem Maße statisch analysieren kann, wie es bei Java der Fall ist.

Was die aus UML-Diagrammen generierte Dokumentation betrifft, so ist das aller Wahrscheinlichkeit nach bestenfalls API-Dokumentation auf niedrigstem Niveau. Sie beschreibt den idealisierten "Soll"-Zustand des Modells, aber nicht den tatsächlichen "Ist"-Zustand einer konkreten Implementierung mit all ihren Besonderheiten und Randbedingungen. Außerdem beschreibt sie nur, welche Methoden eine Klasse hat, nicht aber im Sinne einer Einführung oder eines Tutoriums, wie man diese Methoden im Verbund mit anderen Klassen und Funktionen sinnvoll einsetzen könnte. Etwas wie das Tutorial der Django-Dokumentation kann man nicht aus Diagrammen generieren. Außerdem würde mich interessieren, ob diese "Dokumentation" dann auch in den Docstrings des generierten Codes auftaucht.
Antworten