Also wird jede Zahl im Code, die wir als Argument an eine Methode senden, als magische Zahl betrachtet? Für mich sollte es nicht. Ich denke, wenn irgendeine Zahl ist, sagen wir, es ist für die minimale Länge des Benutzernamens und wir beginnen, "6" im Code zu verwenden ... dann haben wir ja ein Wartungsproblem und hier ist "6" eine magische Zahl ... aber Wenn wir eine Methode aufrufen, bei der eines ihrer Argumente beispielsweise eine Ganzzahl als i-tes Mitglied einer Auflistung akzeptiert, und dann "0" an diesen Methodenaufruf übergeben, sehe ich in diesem Fall diese "0" nicht als Magie Nummer. Was denkst du?
programming-practices
Blake
quelle
quelle
Antworten:
Wenn die Bedeutung der Zahl im Kontext sehr klar ist, halte ich es nicht für ein "magisches Zahlenproblem".
Beispiel: Angenommen, Sie versuchen, die Teilzeichenfolge einer Zeichenfolge vom Anfang bis zu einem Token abzurufen, und der Code sieht folgendermaßen aus (imaginäre Sprache und Bibliothek):
In diesem Zusammenhang ist die Bedeutung der Zahl 0 klar genug. Ich nehme an, Sie könnten es definieren
START_OF_SUBSTRING
und auf 0 setzen, aber in diesem Fall wäre es ein Overkill (obwohl es der richtige Ansatz wäre, wenn Sie wüssten, dass der Anfang Ihrer Teilzeichenfolge möglicherweise nicht 0 ist, aber das hängt von den Besonderheiten von ab deine Situation).Ein anderes Beispiel könnte sein, wenn Sie versuchen festzustellen, ob eine Zahl gerade oder ungerade ist. Schreiben:
ist nicht so seltsam wie:
Negative Zahlen testen als
fühlt sich auch komisch an für mich, ich würde viel lieber sehen
quelle
360
zu verwenden, die eine vollständige Rotation kennzeichnet, mit dem Verständnis, dass die meisten Leute wissen, was das bedeutet (obwohl dies der Fall ist) ist ein Fall, in dem es nicht schaden würde , eine Konstante bereitzustellen)0
im Zusammenhang mit meinem Teilstring-Beispiel ersetzen . In diesem Fall ist dies möglicherweise der geringste Schaden, den sie verursachen können. Es ist lange her, dass ich eine Codierung durchgeführt habe, die geometrische Berechnungen durchgeführt hat, aber im Allgemeinen waren die Werte 15, 30, 45, 60, 90, 180, 360 Konstanten, die akzeptiert wurden. Ich habe noch nie jemanden definieren gesehenFIFTEEN_DEGREES
, ...Es ist offensichtlich, dass Null Abwesenheit bedeutet. Ich finde 0 leichter zu verstehen als eine Variable mit dem Namen "absenceValue".
Es ist offensichtlich, dass 0 die Startposition ist. Ich würde durch eine Variable mit dem Namen "firstPosition" verwirrt. Eine solche Variable würde mich fragen lassen, ob sich die Ausgangsposition ändern könnte.
quelle
Ich würde drei Schlüsselfaktoren vorschlagen, um zu entscheiden, ob etwas eine konstante Deklaration sein soll:
So etwas wie pi sollte wahrscheinlich als benannte Konstante und nicht als numerisches Literal geschrieben werden, da ein numerisches Literal dazu neigt, unnötig wortreich, unnötig ungenau oder beides zu sein. Etwa die Anzahl der Slots in einem Cache sollte wahrscheinlich eine benannte Konstante sein (siehe Hinweis unten), damit der Cache erweitert werden kann, ohne den gesamten Code ändern zu müssen, der ihn verwendet. Dinge wie die Zahlen "4", "28" und "29" in der Anweisung
if ((year % 4)==0) FebruaryDays = 29; else FebruaryDays = 28;
sollten wahrscheinlich nicht als Konstanten bezeichnet werden, da der Ausdruck mit ziemlicher Sicherheit lesbarer ist alsif ((year % YearsBetweenLeapYears)==0) FebruaryDays = FebruaryDaysInLeapYear; else FebruaryDays = FebruaryDaysInNonLeapYear;
. Beachten Sie, dass die Verantwortlichen der Standards angegeben haben, dass die Länge von Februar 2100 in diesem Jahr nicht mit der obigen Formel übereinstimmt. Hindernis für die korrekte Behandlung solcher Daten (dh der Code wird nicht durch einen Ganzzahlüberlauf oder andere derartige Probleme ausgelöst).Eine wichtige Einschränkung bei Regel Nr. 2 ist, dass Code in einigen Fällen auf hartcodierte Zahlen zurückgreifen kann, die nicht ohne weiteres durch eine benannte Konstante dargestellt werden können. Beispielsweise ist eine Methode, die ein Kreuzprodukt von zwei als diskrete Parameter übergebenen Vektoren berechnet, nur bei dreidimensionalen Vektoren sinnvoll. Die erforderliche Anzahl von Dimensionen ist kein Wert, der sinnvoll geändert werden könnte, ohne die Routine vollständig neu zu schreiben. Selbst wenn man einen möglichen Bedarf für die Berechnung des Kreuzprodukts dreier vierdimensionaler Vektoren voraussah, würde die Verwendung einer benannten Konstante für den Wert "3" wenig dazu beitragen, diesen Bedarf leichter zu befriedigen.
quelle
Dies ist, wie alle Prinzipien, eine Frage des Grades. Im Allgemeinen sind Zahlenliterale im Quellcode umso verdächtiger, je größer sie sind. Eine maximale Länge von 10 oder eine Speicheradresse von 0x587FB0 sind offensichtlich eine schlechte Praxis - es ist fast sicher, dass Sie diese Werte früher oder später mehrmals wiederholen müssen, wodurch das Risiko von Inkompatibilität und subtilen Fehlern besteht, die an anderen Stellen auftreten geändert.
0 ist am anderen Ende der Skala; es ist immer noch verdächtig, aber nicht ganz so viel. Verwenden Sie 0 als Sentinel-Wert? Dann sollten Sie wahrscheinlich stattdessen eine symbolische Konstante verwenden, nur weil die Konstante erklären kann , was sie bedeutet. Handelt es sich um eine tief verwurzelte kulturelle Vereinbarung wie "0 bedeutet erfolgreichen Abschluss"? Das ist wahrscheinlich in Ordnung. Bedeutet das "der erste Gegenstand in einer Sammlung"? Das mag harmlos sein, aber wenn es eine alternative Methode gibt,
first()
würde ich das wahrscheinlich vorziehen.quelle
Jede unbenannte Zahl, die aus dem Kontext nicht sofort ersichtlich ist, ist eine magische Zahl. Es ist ein bisschen albern, Zahlen zu definieren, die eine Bedeutung haben, die sich unmittelbar aus dem Kontext ergibt.
In Django (Python Web Framework) kann ich ein Datenbankfeld mit einer unformatierten Zahl wie der folgenden definieren:
Was ist klarer (und die empfohlene Praxis ) als sagen
da ich wohl nie die länge ändern muss (und immer mit der
max_length
des feldes vergleichen kann ). Wenn ich die Länge des Felds nach der ersten Bereitstellung der Anwendung ändern muss, muss ich es in meinem Django-Code an genau einem Ort pro Feld ändern und dann zusätzlich eine Migration schreiben, um das Schema der Datenbank zu ändern. Wenn ich jemals zu Referenz mußmax_length
eine definierten Feld einer Art von Objekt, kann es es direkt tun - wenn diese Felder einen wurden die Definition derPerson
Klasse, kann ichPerson._meta.get_field('firstname').max_length
das erhaltenmax_length
verwendet werden (die an einer Stelle definiert ist). Die Tatsache, dass dieselbe 40 für mehrere Felder verwendet wurde, ist irrelevant, da ich sie möglicherweise unabhängig voneinander ändern möchte. Die Länge des Vornamens sollte niemals von der Länge des Zwischennamens oder des Nachnamens abhängen. Sie sind separate Werte und können sich unabhängig voneinander ändern.Häufig können Array-Indizes unbenannte Zahlen verwenden. Zum Beispiel, wenn ich eine CSV-Datei mit Daten habe, die ich in ein Python-Wörterbuch einfügen möchte, mit dem ersten Element in der Zeile als dem Wörterbuch, das
key
ich schreiben würde:Klar, ich könnte
index_column = 0
etwas benennen und tun wie:oder schlimmer definieren
after_index_col = index_col + 1
, um das loszuwerdenindex_col+1
, aber das macht den Code aus meiner Sicht nicht klarer. Auch wenn ichindex_col
einen Namen gebe , lasse ich den Code besser funktionieren, auch wenn die Spalte nicht 0 ist (daher derrow[:index_col] +
Teil).quelle
max_lngth=40
vs.max_length=MAX_LENGTH_NAME
ein klassisches Beispiel für eine magische Zahl, die schreit , ein Symbol zu sein. Der Tag wird kommen, an dem Sie 45 Zeichennamen unterstützen möchten, und jetzt ist jede Verwendung von "40" verdächtig und muss sorgfältig geprüft werden.40
soll1
. Man muss an den Kontext denken.