Datentyp explizit zuweisen

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
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

Hallo Wissende,

(wie) kann ich einen Datentyp explizit einer Variablen zuweisen?

Einerseits möchte ich damit eclipse die Möglichkeit zu geben, mich zu unterstützen, um in einem viele Zeilen langen Code nicht immer nachsehen zu müssen, wie ich eine Methode gerade genannt habe.
Andererseits verringert das natürlich auch den hä- Effekt beim Programmieren.

Vielen Dank
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Jedes Objekt hat einen eindeutigen Typ, mehr kannst du im allgemeinen Fall nicht erwarten. Wenn du "Variablen" (eigentlich gibt es das in Python nicht, nur Namen, welche auf Objekte referenzieren) zwanghaft einen festen Typ zuweisen willst, dann wirst du mit Python nicht glücklich werden.
Das Leben ist wie ein Tennisball.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

NoPy hat geschrieben:(wie) kann ich einen Datentyp explizit einer Variablen zuweisen?

Code: Alles auswählen

i = 0  # i ist vom Typ Integer
i = 'foo'  # i ist vom Typ String
Das war aber wahrscheinlich nicht das, was du gemeint hast. Ich vermute, du möchtest den Typ einer Variablen deklarieren. Das wiederum widerspricht dem Konzept von Python und geht daher bewusst nicht.

Wenn du dich in deinem Code nicht gut zurecht findest, dann ist das vielleicht eher ein Problem deines Codes (zu lange Funktionen, ungünstige Bezeichnernamen, unvollständige Dokumentation, ...).
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

ich weiß, ich bin jetzt der Böse, aber nein, darum geht es nicht.

Code: Alles auswählen

class XYZ(object):
  def IrgendEineFunktion(self):

#...
#sehr viel Code, vielleicht auch sehr viel Zeit
#...


a=XYZ() # funktioniert, eclipse bietet mir bei a. die Function "IrgendEineFunktion" an, sogar mit Parametern
b=a # und schon funktioniert es nicht mehr
# abgesehen davon fände ich es gut, wenn ich auch wirklich nur XYZs an b übergeben könnte, das verringert den "hä?"- Effekt

gibt es einen Trick, wie man so dokumentieren kann, dass eine Editor- Unterstützung funktioniert?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

NoPy hat geschrieben: gibt es einen Trick, wie man so dokumentieren kann, dass eine Editor- Unterstützung funktioniert?
Ich wüßte keinen!

Aber wie sollte denn etwas anderes als ``XYZ`` an ``b`` übergeben werden können, ohne dass Du es *selber* tust? Und als Benutzer Deiner API solltest Du wohl wissen, was Du da zuweist... und ein anderer sollte aufgrund der *Lesbarkeit* Deiner API leicht ersehen können, was er übergeben darf.

Wie schon erwähnt: Löse Dich mal von den Zwängen, die Du von statisch typisierten Sprachen gewöhnt bist! In Python hast Du eben keine typisierten Variablen, sondern kann alles mögliche an ein und denselben Namen binden. Damit brauchst Du keine Interfaces usw. mehr, sondern kannst beliebige Objekte an Funktionen übergeben, die einfach ein "passendes" Verhalten haben. Das Prinzip dahinter nennt sich übrigens "Duck Typing".
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@NoPy: in Python heißen Datentypen Klassen und das sind genauso Objekte und zuweisen tut man sie explizit so:

Code: Alles auswählen

a = int
b = type("bla")
Python-Programmierer sollten in der Regel ihre Funktionen so schreiben, dass nicht Argumente eines bestimmten Typs erwartet werden, sondern solche mit einem bestimmten Verhalten. Den Typ fest vorzuschreiben ist also schlechter Stil.

Eclipse (genauer pydev) versucht durch Code-Analyse den Typ einer Variable herauszubekommen und kann das in der Regel auch recht zuverlässig. Du mußt auch nicht wissen, welchen Typ eine Variable 1000 Zeilen vor der aktuellen Zeile hat, weil Deine Funktion maximal wenige Handvoll Zeilen hat und das noch leicht zu überblicken ist.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@noPy: Dein Beispiel funktioniert bei mir ohne Probleme:
Bild
BlackJack

@NoPy: Dieser Hä-Effekt sollte eigentlich nicht oft passieren. Das ist nicht selten die Befürchtung von Leuten die *glauben* das einem ständig der Himmel auf den Kopf fallen würde wenn der Compiler nicht verhindert das man falsche Typen übergibt, in der Praxis ist das aber normalerweise kein Problem. Und es erlaubt so wunderbare Sachen wie das Übergeben von Objekten von *irgendeinem* Typ der das erwartete Verhalten an den Tag legt. Das erwähnte „duck typing” eben.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

Ich verstehe, dass ihr mich "pythonisieren" wollt, aber mein Problem ist, dass ich python nutzen "muss" und versuche, es "artgerecht" zu nutzen. Ich werde mich also demnächst mit Euren Bezeichnerempfehlungen vertraut machen, ganz klar.

Mir ist klar, dass es auch Vorteile gibt, wenn man keine expliziten Typen deklarieren muss. Aber im Moment kann ich noch nicht erkennen, wie man effektiv "größere" Projekte stemmen kann, wenn man nicht explizit Festlegungen über interfaces treffen kann. Ich erhalte ja erst eine Fehlermeldung, wenn der Interpreter an einer fehlerhaften Stelle ankommt bzw. an einer Stelle ankommt, die bei einem bestimmten Programmzustand zu Problemen führt. (Ich stoße im Moment beispielsweise permanent auf Probleme mit None- Werten, die ich sicher selbst gebaut habe, aber nicht wirklich zweckmäßig überprüfen kann, ohne überall ein if bla=None: -Achtung, dieser Zustand dürfte eigentlich nie eintreten hinzuschreiben und selbst da weiß ich nicht ohne weiteres, wie ich da hingekommen bin.

Wie ist das gemeint, dass ich Argumente mit einem bestimmten Verhalten erwarten soll? Wie kann ich das "Verhalten" eines Objektes deklarieren? Es geht ja nicht nur darum, innerhalb der Funktion sicherzustellen, die passenden Argumente zu haben, sondern auch darum, einer Funktion nur erwartete Elemente zu übergeben (letzteres ist für mich sogar wichtiger, denn ich benutze mehr Funktionen anderer, als ich selbst schreibe. Und wenn ich zu jeder Funktion, die eigentlich selbsterklärend zu sein scheint, erst Dokumentation finden muss, die mir über die erwarteten Argumente Auskunft gibt, dann ist natürlich ein großer Vorteil der wenigen Zeilen wieder hinfällig, oder etwa nicht?
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@NoPy: Wenn Du Funktionen anderer benutzen sollst, kommt derjenige, der die Funktion schreibt, nicht um eine Dokumentation drumrum. Das wird in Python mit einem doc-String gemacht, der dann natürlich das erwartete Verhalten der Argumente beschreiben muss.
Gerade bei größeren Projekten ist das Testen ein wichtiger Schritt. Wenn Du unit-Tests schreibst, dann fällt recht schnell auf, wenn eine Funktion mit bestimmten Argumenten, die gültig sein sollen, nicht zurechtkommt. In Python muss sich der Programmierer halt stärker an Konventionen halten, als dass er vom Compiler gezwungen wird, sich konform zu verhalten. Mit dieser größeren Freiheit lassen sich viele Probleme aber auch eleganter lösen.

PS: bei Python handelt es sich nicht um einen Interpreter, sondern um einen Compiler, der den Quelltext zur Laufzeit in Instruktionen für eine virtuelle Maschine übersetzt.
BlackJack

@NoPy: Grössere Projekte stemmt man in dem man nicht den Compiler Typen prüfen lässt sondern selber mit Unittests das Verhalten prüft. Das macht man ja sowieso in grösseren Projekten, auch wenn man eine Programmiersprache mit statischen Typen verwendet, denn die Sache mit dem „huch wie bin ich denn in *den* Zustand gekommen” kann einem eine Typprüfung ja auch nicht ersparen, da muss man schon das Verhalten prüfen.

Um das lesen der Dokumentation kommt man nicht herum. Kommt man aber auch selten in statisch typisierten Programmiersprachen.

Das mit den `None`-Werten klingt für mich erst einmal ungewöhnlich. Also im Zusammenhang mit dem Wort „permanent”. Ich würde schon sagen das man auch auf illegale Zustände explizit prüfen sollte und entsprechende Ausnahmen auslösen sollte wenn man in einen gerät. Hier unterscheidet sich Python auch nicht von statisch typisierten Sprachen wie C++ oder Java, denn `None` entspricht semantisch ja in etwa ``null`` und da muss man auch in Java aufpassen und explizit prüfen wenn man nicht bei illegalen Zuständen in ``NullPointerException``\s rennen will.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

Grundsätzlich habt ihr schon recht, Dokumentation und Unittests braucht man bei größeren Projekten. Aber meine None- Werte sind oft durch diverse python- "features" zustandegekommen, die in fest typisierten Sprachen mit dem damit verbundenen Deklarationszwang so nicht passieren würden:

Code: Alles auswählen

#Unterschiedliche Schreibweisen, beabsichtigt oder Schreibfehler
def Schreibweise():
  RichtigGeschrieben = None
  if True:
    RichtigGeschreiben = 8
  return RichtigGeschrieben

a=Schreibweise()

#erzwungenes self innerhalb von Methoden
class IrgendWas(object):
  x=None
  def SetzeWert(self,wert):
    x=wert #syntaktisch korrekt, semantisch sinnlos
  def SetzeWertRichtig(self,wert):
    self.x=wert #so geht es richtig
  def GibWert:
    return self.x

#globale Spielchen

globaleVariable = None

def MachWasMitGlobalerVariable(wert):
  globaleVariable = wert #global vergessen, syntaktisch wieder so korrekt, wie semantisch sinnlos

def GibGlobaleVariable():
  global globaleVariable
  return globaleVariable #hier meckert das System, daher fällt auf, wenn global vergessen wurde

MachWasMitGlobalerVariable(10)
print 'überrascht?',GibGlobaleVariable()
Mir ist klar, dass das alles Fehler des Entwicklers sind, aber eben auch (unnötige?) Stolperfallen
Oder kann mir jemand für diese 3 Fälle einen plausiblen Grund nennen, warum es so sein sollte?

Zum Thema Interpreter/Compiler: Es ist in meinen Augen ein Interpreter. Ein Compiler würde ERST übersetzen und dann abarbeiten. Wenn Du am Ende Deines Python- Modules einen Schreibfehler einbaust, dann wird das Programm bis dahin durchlaufen, ehe es merkt, dass es gar keinen Code gibt, der mit einem Symbol verbunden ist. Und das Argument "na ja, es könnte ja sein, dass das Objekt eine solche Methode hat, dass dort übergeben wird" zieht nicht. Selbst der Aufruf eines globalen Symbols (Funktion, Variable ...) fällt erst dann auf.
Das hat mich fast zur Verzweiflung getrieben, als ich WebServices ansprechen wollte. Immer, wenn ich etwas installiert hatte, dann fiel erst zur Laufzeit auf, dass noch Module nötig waren, die ich noch nicht installiert hatte. Und final landete ich dann oft bei Modulen, die zu den Vorgängerversionen nicht passten ... Und als ich mal alles zu haben glaubte, trat das Problem mit fehlenden Modulen bei einer bestimmten Konstellation auf.
Zumindest die Compiler, die ich kenne, hätten das schon eher bemerken können. Vermutlich ist das bei Python aber prinzipiell nicht oder nur schwer realisierbar, weil ja nicht allein vom Quelltext sondern auch von den Eingangsdaten abhängen kann, welches konkretes Objekt mit welchen Symbolen zu einem bestimmten Zeitpunkt in einer Variable steckt. So gesehen kann python gar nicht compiliert werden, ohne dass entweder viele Zweige durchgespielt werden oder zumindest rudimentäre Beschneidungen vorgenommen werden a la 'liste alle möglichen Symbole (Attribute, Methoden aller Klassen, globale Funktionen und Variablen) auf und meckere über alles, was nicht mindestens ein mal vorkommt' und selbst das kann nicht ausschließen, dass ein Objekt ankommt, dass zur Laufzeit nicht über die verfügbaren Symbole verfügt.

Eigentlich hätte - jetzt betrachtet - das Thema heißen sollen: Deklarationszwang für Symbole möglich?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

NoPy hat geschrieben: Mir ist klar, dass das alles Fehler des Entwicklers sind, aber eben auch (unnötige?) Stolperfallen
Beim Programmieren macht (fast) immer der Entwickler den Fehler ;-) Aber genau dafür gibt es ja Instrumente wie Unit-Tests.
NoPy hat geschrieben: Zum Thema Interpreter/Compiler: Es ist in meinen Augen ein Interpreter. Ein Compiler würde ERST übersetzen und dann abarbeiten.
Och nö... wieso wollen so viele selber eine "persönliche" Definition für gängige Konzepte wie Compiler und Interpreter aufstellen? Im übrigen widersprichst Du Dir hier selber, falls es Dir nicht schon aufgefallen ist :twisted:

Wie gesagt: Wenn Du Dich nicht auf die Besonderheiten einer Sprache einlassen willst, in diesem Falle geht es ja sogar um das allgemeine Paradigma der dynamischen Typisierung, dann nimm doch einfach eine andere Sprache ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Programmierfehler macht man in jeder Sprache. Ich würde sogar sagen, dass man in Python tendenziell weniger Fehler macht, da man insgesamt weniger Zeilen Code schreiben muß. Zu Deinen Fehlern: solche Fehler werden durch gute Unit-Tests sofort erkannt. Mein Editor kennzeichnet sogar Unbenutzte oder nicht-zugewiesene Variablen, das reduziert die Anzahl der Test-Läufe dann deutlich ;-)
»global« ist ein Schlüsselwort, das in normalen Programmen nicht vorkommt. Globale Variablen sind KONSTANTEN und die erkennt man an der Großschreibung oder Funktionen und die erkennt man daran, dass sie eine Tätigkeit beschreiben.
Probleme mit fehlenden Modulen oder falschen Versionen hatte ich mit Python seltener als mit C.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

NoPy hat geschrieben:Mir ist klar, dass das alles Fehler des Entwicklers sind, aber eben auch (unnötige?) Stolperfallen
Oder kann mir jemand für diese 3 Fälle einen plausiblen Grund nennen, warum es so sein sollte?
1. Fall, ja das ist doof. 2. & 3. Fall warum sollte das ein Fehler sein? Warum sollte ich mit einer lokalen Variable keine globale überschreiben dürfen? Das ist verdammt nochmal der Sinn von lokalen Variablen.
Zum Thema Interpreter/Compiler: Es ist in meinen Augen ein Interpreter. Ein Compiler würde ERST übersetzen und dann abarbeiten. Wenn Du am Ende Deines Python- Modules einen Schreibfehler einbaust, dann wird das Programm bis dahin durchlaufen, ehe es merkt, dass es gar keinen Code gibt, der mit einem Symbol verbunden ist. Und das Argument "na ja, es könnte ja sein, dass das Objekt eine solche Methode hat, dass dort übergeben wird" zieht nicht. Selbst der Aufruf eines globalen Symbols (Funktion, Variable ...) fällt erst dann auf.
Das hat mit Interpretieren vs. Kompilieren nichts zu tun. Das liegt einzig und allein daran, wie Python Namen auflöst. Solche Fehler können erst zur Laufzeit auffallen, da der Compiler nicht wissen kann ob der Name zur Laufzeit vorhanden ist oder nicht. Deswegen kann ein Python-Compiler nur Syntaxfehler feststellen.
Zumindest die Compiler, die ich kenne, hätten das schon eher bemerken können. Vermutlich ist das bei Python aber prinzipiell nicht oder nur schwer realisierbar, weil ja nicht allein vom Quelltext sondern auch von den Eingangsdaten abhängen kann, welches konkretes Objekt mit welchen Symbolen zu einem bestimmten Zeitpunkt in einer Variable steckt.
Richtig, es ist bei Python prinzipiell nicht möglich. Man kann nur raten und das ist, was Eclipse o.ä. versuchen.
So gesehen kann python gar nicht compiliert werden, [...]
Ich glaube eher deine Vorstellung was ein Kompilationsvorgang ist entspricht nicht der gängigen Definition. Hint: Siehe ObjC ist unzweifelhaft eine kompilierte Sprache aber trotzdem können zur Laufzeit "komische" Fehler auftreten dass Objekte einen anderen Typ haben als vorgesehen und trotzdem alles funktioniert wie gedacht.
Eigentlich hätte - jetzt betrachtet - das Thema heißen sollen: Deklarationszwang für Symbole möglich?
Kurze Antwort: NEIN. Lange Antwort: Benutze nicht Python.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

@hyperion: nicht persönliche Definition, sondern interpretation des Gesehenen.
http://de.wikipedia.org/wiki/Compiler#Arbeitsweise

Schritt 1) Festgestellt Syntax-Fehler werden protokolliert ... Das ist bei mir so nicht. Wenn ich an keinem Syntaxfehler vorbeikomme, wird nichts protokolliert. Protokolliert wird erst, wenn die fehlerhafte Zeile benutzt wird - also zur Laufzeit ;)

@Sirius: Mag sein, dass ich mich noch daran gewöhnen muss, aber ich brauche für die wenigen Zeilen länger, als für mehr Zeilen in beispielsweise dem gesprächigen Delphi, u.a. weil ich sehr komplexe Klassen haben kann, deren "passende" Funktionen/Attribute mir die IDE herausfiltern kann UND ich keinerlei Probleme mit Verschreibern haben muss. Probleme mit falschen/fehlenden Modulen hatte ich in anderen auch, aber eben nicht erst zur Laufzeit.
Mein Editor kennzeichnet sogar Unbenutzte oder nicht-zugewiesene Variablen, das reduziert die Anzahl der Test-Läufe dann deutlich
Macht eclipse glücklicherweise auch, aber es lässt sich der Fall konstruieren, wo solche Fehler unbemerkt bleiben, auch von eclipse

Code: Alles auswählen

Test=None
if True:
  Toast=12
else:
  Test=-12
if True:
  return Toast*2
else
  return Test/2
ist also in meinen Augen nur die zweitbeste Lösung

@Darii:
1. Fall, ja das ist doof. 2. & 3. Fall warum sollte das ein Fehler sein? Warum sollte ich mit einer lokalen Variable keine globale überschreiben dürfen? Das ist verdammt nochmal der Sinn von lokalen Variablen.
Fall 2 und 3 sind für sich genommen keine Fehler, aber Fehler damit entstehen eben dadurch, dass ich nicht explizit deklarieren KANN. Wenn ich in einer Methode eine Variable deklariere, dann weiß ich, dass ich eine evtl. vorhandene globale Variable überschreibe. Wenn ich diese Deklaration vergesse, habe ich das gleiche Problem, nur umgekehrt, ich beschreibe etwas globales, obwohl ich etwas lokales beschreiben will. Global sind bei mir wenige Konstanten, bei denen ich schon am Namen erkennen kann, dass sie global sind, daher würde mir dieser Fehler nicht passieren. Dass ich "global" vergesse, das taucht (noch) häufiger auf.
Das hat mit Interpretieren vs. Kompilieren nichts zu tun. Das liegt einzig und allein daran, wie Python Namen auflöst. Solche Fehler können erst zur Laufzeit auffallen, da der Compiler nicht wissen kann ob der Name zur Laufzeit vorhanden ist oder nicht. Deswegen kann ein Python-Compiler nur Syntaxfehler feststellen.
Das ist m.E. falsch, denn globale Bezeichner können zur Laufzeit nicht hinzukommen. Und auch solche werden erst zur Laufzeit ausfindig gemacht. Python stellt also zumindest nicht alle Syntaxfehler zur Laufzeit fest. Aber letztlich ist es Wurst, ob man das Ding nun als Compiler, Interpreter oder als Zwitter zwischen beiden auffassen will. Darauf kam es mir nicht an, ist mir letztlich nur rausgerutscht.
Ich glaube eher deine Vorstellung was ein Kompilationsvorgang ist entspricht nicht der gängigen Definition. Hint: Siehe ObjC ist unzweifelhaft eine kompilierte Sprache aber trotzdem können zur Laufzeit "komische" Fehler auftreten dass Objekte einen anderen Typ haben als vorgesehen und trotzdem alles funktioniert wie gedacht.
Na ja, das finde ich nun wieder eher unsportlich. Natürlich kann ich Objekte übergeben, die sich zur Laufzeit als unpassend herausstellen. Aber dennoch wird jeder Zweig zur Compile/Build- Zeit in Maschinencode aufgelöst. Dass dann in Bereiche gesprungen werden könnte, die nicht existieren, das ist eine andere Geschichte. Bei Python muss im Grunde zur Laufzeit immer noch ein Teil den Namen des Quellcodes analysieren. Das empfinde ich schon als unterschiedlich.
Antwort ist: NEIN.
Das ist explizit schade, also kann ich nur hoffen, mich möglichst selten zu verschreiben
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

NoPy hat geschrieben:Das ist m.E. falsch, denn globale Bezeichner können zur Laufzeit nicht hinzukommen. Python stellt also zumindest nicht alle Syntaxfehler zur Laufzeit fest.
Doch können sie. Python legt alle Bezeichner in Dictionaries ab (das globale ist zu erreichen über globals() ). Dort kannst du nach Belieben neue Namen reinschreiben. Auch Modulübergreifend. Klingt evil, ist es in 99% der Fälle auch und man sollte genau überlegen ob es nicht auch anders geht. Und genau deswegen kann der Compiler solche Fehler nicht finden. Weil es eben kein Syntaxfehler ist.
Bei Python muss im Grunde zur Laufzeit immer noch ein Teil den Namen des Quellcodes analysieren. Das empfinde ich schon als unterschiedlich.
Nein muss Python nicht. Python guckst nur im Dictionary des dazugehörigen Namensraums nach. Das ist technisch auch nicht anders als ein dynamischer Methodenaufruf in ObjC. Extrembeispiel ist z.B. die Sprache self (u.A. Vorbild für Java und Javascript), dort gibt es keine Variablen nur "slots" die faktisch immer Methodenaufrufen entsprechen.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@NoPy: der Fehler, dass ich ein »global« vergesse, kann mir nie passieren, weil ich, außer in wenigen Ausnahmen, nie »global« benutze. Und die Ausnahmen sind Funktionen, die nur eine globale Variable setzen, also aus maximal 2 Zeilen bestehen. Und genauso solltest Du es auch mit »global« halten. Dass man sich mehrfach verschreibt, wie in Deinem Beispiel, wirkt solangsam wirklich konstruiert. Man kann sich das Leben auch schwer machen, in dem man möglichst undurchschaubaren Code schreibt.
Benutzeravatar
NoPy
User
Beiträge: 158
Registriert: Samstag 28. Dezember 2013, 12:39

@Sirius3
@NoPy: der Fehler, dass ich ein »global« vergesse, kann mir nie passieren, weil ich, außer in wenigen Ausnahmen, nie »global« benutze. Und die Ausnahmen sind Funktionen, die nur eine globale Variable setzen, also aus maximal 2 Zeilen bestehen. Und genauso solltest Du es auch mit »global« halten. Dass man sich mehrfach verschreibt, wie in Deinem Beispiel, wirkt solangsam wirklich konstruiert. Man kann sich das Leben auch schwer machen, in dem man möglichst undurchschaubaren Code schreibt.
Ist bei mir auch so, da geht es um so etwas, wie url zu einem Dienst oder Connect- String für eine Datenbank oder ein Connection- Objekt etc.
Dennoch ist es erst einmal eine Umstellung, weil ich gewohnt bin, explizit zu deklarieren und sich dadurch ein Schlüsselwort "global" entbehrlich macht.

@Darii
Doch können sie. Python legt alle Bezeichner in Dictionaries ab (das globale ist zu erreichen über globals() ). Dort kannst du nach Belieben neue Namen reinschreiben. Auch Modulübergreifend. Klingt evil, ist es in 99% der Fälle auch und man sollte genau überlegen ob es nicht auch anders geht. Und genau deswegen kann der Compiler solche Fehler nicht finden. Weil es eben kein Syntaxfehler ist.
Klingt wirklich schräg ...
Nein muss Python nicht. Python guckst nur im Dictionary des dazugehörigen Namensraums nach. Das ist technisch auch nicht anders als ein dynamischer Methodenaufruf in ObjC. Extrembeispiel ist z.B. die Sprache self (u.A. Vorbild für Java und Javascript), dort gibt es keine Variablen nur "slots" die faktisch immer Methodenaufrufen entsprechen.
Akzeptiert
BlackJack

(Etwas länger weil ich bei einem etwas weiter zurück liegenden Beitrag mit der Antwort angefangen habe. Sorry :-))

@NoPy: Das bei `Schreibweise()` passiert mir nicht; soweit kann man den Programmfluss in Python dann schon analysieren, dass mir der Editor hier schon sagt das `RichtigGeschreiben` etwas zugewiesen wird, was aber nie verwendet wird. Ausserdem kommt es selten vor dass ich einen so langen Namen nicht über die Autovervollständigung „schreibe”. Die braucht dazu noch nicht einmal intelligent sein, sondern kann auch einfach nur bereits vorhandene Worte aus dem oder den offenen Dokument(en) vorschlagen. Das heisst wenn ich Schreibfehler in Namen habe, dann üblicherweise sehr konsequent durch das ganze Programm. :-)

Exakt die gleiche Warnung bekomme ich auch in `SetzeWert()`, denn auch dort wird etwas zugewiesen was nicht verwendet wird. Wobei ich als ersten Fehler hier schon das ``x = None`` auf Klassenebene ansehen würde. Das gehört da nicht hin. Da kommen entweder Konstanten hin oder tatsächliche Klassenvariablen. Im ersten Fall würde es `X` — grossgeschrieben — heissen und im zweiten Fall, der *sehr* selten ist, würde man nicht auch auf den Exemplaren ein Attribut mit dem gleichen Namen haben wollen. Das wäre verwirrend.

Die Klasse würde man in Python so schreiben:

Code: Alles auswählen

class IrgendWas(object):
    def __init__(self):
        self.x = None
Die trivialen Getter/Setter sind unnötige Schreibarbeit. Sollte man irgendwann einmal das Attribut beim Zugriff „berechnen” wollen, ohne Clientcode ändern zu müssen, gibt es `property()` und Dekoratorsyntax.

Wenig überraschend bekomme ich bei `MachWasMitGlobalerVariable()` wieder genau den gleichen Hinweis im Editor, nämlich das eine lokale Zuweisung nicht verwendet wird. Hier ist das eigentliche Problem aber schon einem globalen Namen etwas zuweisen zu wollen. Sehr selten sinnvoll, weil fast immer sauberer lösbar.

Der Kommentar bei `GibGlobaleVariable()` macht keinen Sinn. Was meckert denn Dein System da? Da wird ``global`` überhaupt nicht gebraucht, das verhält sich mit und ohne das Schlüsselwort exakt gleich. Mein Editor meckert mich eher Grundsätzlich an dass dort ``global`` verwendet wird. Eben weil man sich so etwas zwei bis dreimal überlegen sollte ob man wirklich Zustand auf Modulebene haben will.

Das Namen erst zur Laufzeit aufgelöst werden hat nichts mit Compiler oder nicht zu tun. Es gibt auch nach Maschinencode übersetze Sprachen bei denen Namen nicht beim übersetzen gebunden werden. Selbst auf so „low level”-Sprachen wie C trifft das zu, bei dynamisch gebundenen Bibliotheken etwa, da löst der Compiler auch nicht den Funktionsnamen zu einer Adresse auf, und es kann zur Laufzeit passieren, dass das Programm mit einer Meldung aussteigt das eine namentlich genannte Funktion nicht existiert.

Der mittlere Schritt beim Compilieren den Wikipedia angibt — die Zwischendarstellung — ist für einen Compiler nicht zwingend erforderlich. Den gibt es aber beim CPython-Compiler. Der Code wird in einen abstrakten Syntaxbaum übersetzt, bevor daraus der Zielcode generiert wird. Die Module `ast` und `dis` lassen da ein wenig in das „Innenleben” schauen.

Beim Installieren sollte man die Dokumentation lesen was die Module für Abhängigkeiten haben. Das spart einem auch bei statisch kompilierten Sprachen Nerven, denn zum Beispiel ein C- oder C++-Programm immer wieder zu komplilieren bis der erste fehlender Header angemeckert wird, dann die Abhängigkeit zu installieren und wieder bis zum nächsten Compilerfehler und so weiter, ist auch nicht schön. Das Problem mit den Versionsnummern von Bibliotheken hat man dort genau so.

Am besten man verwendet bei einer Linuxdistribution das Paketsystem, oder man verwendet einen Installer der die Abhängigkeiten auflöst, ``pip`` zum Beispiel. Um Python-Projekte mit vielen externen Abhängigkeiten, die man nicht im Python-Package-Index findet und mit ``pip`` & Co installieren kann, würde ich einen Bogen machen.

Irgendwelcher Unsinn lässt sich immer konstruieren. Bei dem Beispiel frage ich mich als erstes warum am Anfang ``test = None`` steht. Und dann würde man das *so* natürlich nicht schreiben sondern so :-):

Code: Alles auswählen

def spam():
    return 24

# oder

SPAM = 24
Ich würde ja mal gerne ein *reales* Beispiel sehen wo die Vermeidung durch eine Typdeklaration besser ist als das so umzuschreiben, so das der Fehler auch anders leicht auffällt. Ich frage das deshalb weil mir so etwas sehr selten passiert und dann fast immer weil der Quelltext einfach zu unübersichtlich ist und man den sowieso mal aufräumen/umschreiben sollte. Bei dem gezeigten Beispiel würde man sich ja zum Beispiel fragen warum es überhaupt zwei potentielle Rückgabewerte gibt, die parallel in verzahntem Quelltext entstehen.

Ich frage mich auch wie eine Typdeklaration hier helfen soll. Denn es ist ja ein Fehler im Programmfluss. Wenn man `test` als Zahl deklarieren muss, würde der Fehler *schlechter* auffindbar sein, denn dann könnte man nicht `None` zuweisen sondern würde an der Stelle eine Zahl zuweisen und die Funktion würde anstandslos durchlaufen, aber ein falsches Ergebnis liefert, was potentiell erst viel später auffällt, oder sogar durchrutscht.

``global`` kann man nicht vergessen, man *sollte* es vergessen. Denn modulglobaler Zustand ist unsauber. Damit schafft man sich Zustand und Abhängigkeiten an einer Stelle die kein Python-Programmierer erwartet. Und damit eine unnötige Fehlerquelle und eine Menge „Hä”-Erlebnisse. :-)

Und ``global`` kannst Du einen Namen ja deklarieren. Das macht man mit dem ``global``-Schlüsselwort. Und diese Richtung ist auch genau die richtige, da weniger fehleranfällig. Sonst müsste man nämlich bei jedem neuen Namen auf Modulebene alle lokalen Namen kennen um sicherstellen zu können, dass man nicht ausversehen etwas kaputt macht.

Deine Beispiele für ``global`` überzeugen mich nicht wirklich. Das kann man doch problemlos in einem Objekt kapseln ohne auf so etwas globales zurück zu greifen. Die Funktion die das mal setzt ist dann die `__init__()` und die Funktionen die darauf zurückgreifen sind die Methoden.

Insgesamt habe ich das Gefühl das Du keinen Python-Code schreibst, sondern versuchst eine andere Sprache, zum Beispiel Delphi, möglichst 1:1 in Python-Syntax und Semantik zu pressen. Wenn sich zwei Programmiersprachen nicht sehr ähnlich sind, geht so etwas selten gut.
Antworten