Ist das Ändern des Typs einer Variablen während einer Prozedur in einer dynamisch typisierten Sprache ein schlechter Stil?

8

In Python (und gelegentlich in PHP), wo Variablen keine festen Typen haben, führe ich häufig 'Typtransformationen' für eine Variable auf halbem Weg durch die Logik meines Codes durch. Ich spreche nicht (unbedingt) von einfachen Casts, sondern von Funktionen, die den Typ einer Variablen ändern, während sie im Grunde den gleichen Wert oder die gleichen Daten darstellen.

Zum Beispiel könnte ich Code wie diesen schreiben, wenn ich eine responseWebanforderung mache, indem ich die Variable zum Speichern eines addurlinfo-Objekts verwende, dann den Zeichenfolgeninhalt dieses Objekts und das Wörterbuch, das durch Parsen der Zeichenfolge als JSON zurückgegeben wird:

response = urlopen(some_url)
assert response.info().type == 'application/json'

response = response.read()
logger.debug('Received following JSON response: ' + response)

response = json.loads(response)
do_something(response)

(Okay, es ist ein leicht erfundenes Beispiel, aber ich denke, es zeigt die Idee gut). Meiner Meinung nach ist dies besser als die Verwendung von drei separaten Variablennamen, da a) die responseVariable im Grunde die gleichen Informationen enthält, nur in einen anderen Typ "transformiert" wurde, und b) die früheren Objekte nicht verwendet werden werden weiter unten in der Funktion benötigt, da ich sie durch Neuzuweisung über ihre Variable für späteren Code nicht verfügbar gemacht habe.

Ich denke, der Nachteil ist, dass der Leser verwirrt sein kann, welcher Typ die Variable zu einem bestimmten Zeitpunkt ist.

Ist das ein schlechter Stil und sollte ich im obigen Beispiel drei verschiedene Variablen verwenden, anstatt sie einer neu zuzuweisen? Ist diese Standardpraxis auch in dynamisch typisierten Sprachen oder nicht? Ich habe nicht genug vom Code anderer Leute gesehen, um es zu wissen.

Mark Amery
quelle

Antworten:

9

Ich werde auf ein Glied gehen und sagen: Nein, das ist eine schreckliche Idee.

Es ist nur ein Sonderfall der Wiederverwendung einer Variablen, was eine schlechte Idee ist - hauptsächlich, weil es schwierig ist zu verstehen, was eine Variable an einem bestimmten Punkt im Programmablauf enthält. Siehe zB Soll ich Variablen wiederverwenden?

Zu Ihren Punkten: Die Punkte, die Sie ansprechen, sind gültig. Die Wiederverwendung der Variablen ist nur keine gute Lösung :-).

a) Es vermittelt, dass die Antwortvariable im Grunde die gleichen Informationen enthält, die nur in einen anderen Typ "transformiert" wurden

Die Bereitstellung dieser Informationen ist eine gute Idee. Verwenden Sie dazu jedoch nicht dieselbe Variable, da Sie dann die Tatsache verschleiern, dass die Informationen transformiert wurden. Verwenden Sie stattdessen Namen mit einem gemeinsamen Prä- / Postfix. In Ihrem Beispiel:

rawResponse = urlopen(some_url)
[...]    
jsonResponse = response.read()
[...]    
responseData = json.loads(response)
[...]

Dies macht deutlich, dass die Variablen eng miteinander verbunden sind, aber auch nicht dieselben Daten enthalten.

b) Es zeigt an, dass die früheren Objekte nicht weiter unten in der Funktion benötigt werden, da ich sie durch Neuzuweisung über ihre Variable für späteren Code nicht verfügbar gemacht habe.

Auch hier ist es gut, dies "nicht mehr benötigt" zu kommunizieren, aber tun Sie es nicht, indem Sie die Variable wiederverwenden: Die Zuweisung der Wiederverwendung ist normalerweise schwer zu erkennen, sodass Sie den Leser nur verwirren.

Wenn eine Variable lange nach ihrer letzten Verwendung lebt, ist dies ein Hinweis darauf, dass die Methode / Funktion zu lang ist. Teilen Sie das Teil mit den kurzlebigen Variablen in eine Unterfunktion auf. Dies erleichtert das Lesen des Codes und begrenzt die Lebensdauer der Variablen.

Hinweis: Normalerweise gehe ich sogar einen Schritt weiter, als Variablen nicht wiederzuverwenden, und versuche, einen Wert nur einmal zuzuweisen (dh den Wert niemals zu ändern, ihn unveränderlich zu machen). Dies ist eine Idee, die hauptsächlich aus funktionalen Sprachen stammt, aber ich fand, dass sie Code viel klarer machen kann. Natürlich müssen Sie in nicht funktionierenden Sprachen manchmal eine Variable ändern (ein offensichtliches Beispiel ist eine Schleifenvariable), aber sobald Sie anfangen zu suchen, werden Sie feststellen, dass eine "frische" Variable in den meisten Fällen besser lesbar und weniger lesbar ist Fehleranfälliger Code.

sleske
quelle
6

Ich weiß, dass Sie in Ihrem Beispiel von einer URL lesen, aber wenn Sie dasselbe mit einer Datei versucht haben, können Sie die Datei nicht schließen, da die Antwort nicht mehr auf die Datei zeigt. Sie enthält jetzt einen Stich, den Sie abgerufen haben aus der Datei.

Das ist die große Gefahr, Sie könnten vergessen, welchen Wert es hat, weil es sich während der Lebensdauer des Programms oder Moduls ändert. Es ist verwirrend für jemanden, der Ihren Code liest, weil er nie weiß, welchen Werttyp er enthält.

Dies sind die lustigen Bugs, die versuchen, zu quetschen.

mhoran_psprep
quelle
4

Im Allgemeinen würde ich ja sagen, es ist ein schlechter Stil, aber es gibt Fälle, in denen es notwendig und nützlich ist, eine Variable wiederzuverwenden. Ich würde nur empfehlen, den gelegentlichen, faulen Gebrauch davon zu vermeiden.

Das Problem mit Ihrem Beispiel liegt nicht in der dynamischen Typisierung, sondern darin, dass Sie dieselbe Variable verwenden, um auf drei verschiedene Dinge zu verweisen. Dieser Code ist mir weniger klar, weil ich beim Lesen viel genauer nachdenken muss, um herauszufinden, worauf er sich responsebezieht.

Sie könnten in einer statisch typisierten Sprache wie Java etwas ähnlich Böses tun (mit der Einschränkung, dass die verschiedenen Dinge durch eine Typhierarchie miteinander verbunden sind). Der entscheidende Punkt ist, dass die Verwendung einer einzelnen Variablen zum Zeigen auf verschiedene Objekte unabhängig vom Typsystem verwirrend sein kann.


quelle
Dies scheint ein vernünftiger Einwand zu sein, und ich denke, ich werde versuchen, diese Art von Stil aus meinem Code herauszulösen. Follow-up: Wie würden Sie verschiedene Variablen benennen, die sich konzeptionell auf dasselbe beziehen, aber unterschiedliche Typen haben? Ungarische Notation ist eine Art hässlich und Typen Hinter (wie mit response_addurlinfo, response_str, response_dict) sind noch hässlicher. Wie geht's?
Mark Amery
@ MarkAmery Ich denke, der Schlüssel ist, dass sich die Variablen konzeptionell nicht auf dasselbe beziehen. Die erste ist nur eine Serverantwort, die ein Fehler sein kann, die zweite ist eine Textzeichenfolge, die möglicherweise nicht gültig ist, und die dritte ist eine Datenstruktur. Es gibt mehr Semantik als nur eine Antwort und einen Typ. Nach meiner Erfahrung ist eine gute Benennung von Variablen sehr schwierig, lohnt sich aber normalerweise. Entschuldigung, ich kann nicht konkreter sein!