Wie kann bei einem beliebigen Python-Objekt am besten festgestellt werden, ob es sich um eine Zahl handelt? Hier is
ist definiert als acts like a number in certain circumstances
.
Angenommen, Sie schreiben eine Vektorklasse. Wenn Sie einen anderen Vektor angeben, möchten Sie das Punktprodukt finden. Wenn Sie einen Skalar erhalten, möchten Sie den gesamten Vektor skalieren.
Prüfen , ob etwas ist int
, float
, long
, bool
ärgerlich und deckt keine benutzerdefinierten Objekte , die wie Zahlen handeln könnte. Das Überprüfen auf __mul__
zum Beispiel ist jedoch nicht gut genug, da die soeben beschriebene Vektorklasse definieren würde __mul__
, aber es wäre nicht die Art von Zahl, die ich möchte.
isinstance(value, Number) and type(value) != bool
Sie möchten überprüfen, ob ein Objekt vorhanden ist
Wenn Sie Python 2.5 oder älter verwenden, besteht die einzige Möglichkeit darin, einige dieser "bestimmten Umstände" zu überprüfen und zu überprüfen.
In 2.6 oder besser können Sie
isinstance
mit numbers.Number verwenden - eine abstrakte Basisklasse (ABC), die genau für diesen Zweck existiert (es gibt viel mehr ABCs in dercollections
Modul für verschiedene Arten von Sammlungen / Containern, wiederum beginnend mit 2.6; und, Auch nur in diesen Releases können Sie bei Bedarf problemlos Ihre eigenen abstrakten Basisklassen hinzufügen.Bach bis 2.5 und früher, "kann hinzugefügt werden
0
und ist nicht iterierbar", könnte in einigen Fällen eine gute Definition sein. Aber, die Sie wirklich brauchen , sich zu fragen, was es ist , dass Sie fragen, was Sie „eine Reihe“ betrachten wollen definitiv in der Lage sein müssen , zu tun , und was es muss absolut sein nicht in der Lage zu tun - und überprüfen.Dies kann auch in Version 2.6 oder höher erforderlich sein, um möglicherweise eigene Registrierungen vorzunehmen, um Typen hinzuzufügen, für die Sie sich interessieren und die noch nicht registriert sind
numbers.Numbers
- wenn Sie einige Typen ausschließen möchten, die behaupten, sie seien Zahlen, aber Sie kann einfach nicht damit umgehen, das ist noch sorgfältiger, da ABCs keineunregister
Methode haben [[zum Beispiel könnten Sie Ihr eigenes ABC erstellenWeirdNum
und dort all diese für Sie seltsamen Typen registrieren, und dann zuerst prüfen, obisinstance
sie gerettet werden, bevor Sie fortfahren um nachisinstance
dem Normalennumbers.Number
zu suchen , um erfolgreich fortzufahren.Übrigens, wenn Sie prüfen müssen, ob etwas möglich
x
ist oder nicht, müssen Sie im Allgemeinen Folgendes ausprobieren:Das Vorhandensein von
__add__
per se sagt Ihnen nichts Nützliches, da z. B. alle Sequenzen es zum Zwecke der Verkettung mit anderen Sequenzen haben. Diese Prüfung entspricht beispielsweise der Definition "Eine Zahl ist so, dass eine Folge solcher Dinge ein gültiges Einzelargument für die eingebaute Funktion istsum
". Völlig seltsame Typen (z. B. solche, die die "falsche" Ausnahme auslösen, wenn sie auf 0 summiert werden, wie z. B. aZeroDivisionError
oder "nicht iterierbar sein") (z. B. überprüfen, ob dies ausgelöst wird , oder auf das Vorhandensein einer speziellen Methode - wenn Sie in 2.5 oder früher sind und daher Ihre eigenen Schecks benötigen).ValueError
& c) verbreiten eine Ausnahme, aber das ist in Ordnung. Lassen Sie den Benutzer so schnell wie möglich wissen, dass solche verrückten Typen im Guten einfach nicht akzeptabel sind Unternehmen;-); Aber ein "Vektor", der zu einem Skalar summierbar ist (Pythons Standardbibliothek hat keinen, aber natürlich sind sie als Erweiterungen von Drittanbietern beliebt), würde hier auch das falsche Ergebnis liefern, also (ziter(x)
TypeError
__iter__
Ein kurzer Blick auf solche Komplikationen kann ausreichen, um Sie zu motivieren, sich nach Möglichkeit auf abstrakte Basisklassen zu verlassen ... ;-).
quelle
Dies ist ein gutes Beispiel, wo Ausnahmen wirklich glänzen. Tun Sie einfach, was Sie mit den numerischen Typen tun würden, und fangen Sie das
TypeError
von allem anderen ab.Dies prüft aber natürlich nur, ob eine Operation funktioniert , nicht ob sie sinnvoll ist ! Die einzige wirkliche Lösung dafür besteht darin, niemals Typen zu mischen und immer genau zu wissen, zu welcher Typklasse Ihre Werte gehören.
quelle
isinstance
es in vielen Fällen tatsächlich nützlich sein kann (== "check it sinnvoll" sowie formale Anwendbarkeit von Operationen). Schwierige Verschiebung für langjährige Nur-Python-Leute, aber ein sehr wichtiger subtiler Trend in Pythons Philosophie, dass es ein schwerwiegender Fehler wäre, ihn zu ignorieren.collections.Sequence
und Freunde). Aber afaik, es gibt keine solchen Klassen für Zahlen, Vektoren oder andere mathematische Objekte.Multiplizieren Sie das Objekt mit Null. Jede Zahl mal Null ist Null. Jedes andere Ergebnis bedeutet, dass das Objekt keine Zahl ist (einschließlich Ausnahmen).
Wenn Sie also isNumber verwenden, erhalten Sie die folgende Ausgabe:
Ausgabe:
Es gibt wahrscheinlich einige Nicht-Zahlen-Objekte auf der Welt, die definieren
__mul__
, dass bei Multiplikation mit Null Null zurückgegeben wird, aber das ist eine extreme Ausnahme. Diese Lösung sollte den gesamten normalen und vernünftigen Code abdecken , den Sie generieren / erfassen.numpy.array Beispiel:
Ausgabe:
quelle
True * 0 == 0
int
Wert leitet sich von ab, sodass meine Funktion korrekt sagt, dass Boolesche Werte Zahlen sind.Um Ihre Frage neu zu formulieren, versuchen Sie festzustellen, ob es sich bei etwas um eine Sammlung oder um einen einzelnen Wert handelt. Der Versuch zu vergleichen, ob etwas ein Vektor oder eine Zahl ist, vergleicht Äpfel mit Orangen - ich kann einen Vektor von Zeichenfolgen oder Zahlen haben, und ich kann eine einzelne Zeichenfolge oder eine einzelne Zahl haben. Sie interessieren sich dafür, wie viele Sie haben (1 oder mehr) , nicht welchen Typ Sie tatsächlich haben.
Meine Lösung für dieses Problem besteht darin, zu überprüfen, ob die Eingabe ein einzelner Wert oder eine Sammlung ist, indem ich das Vorhandensein von überprüfe
__len__
. Beispielsweise:Für den Ansatz der Ententypisierung können Sie auch versuchen, zuerst zu iterieren
foo
:Letztendlich ist es einfacher zu testen, ob etwas vektorartig ist, als zu testen, ob etwas skalarartig ist. Wenn Werte unterschiedlichen Typs (z. B. Zeichenfolge, Zahl usw.) durchkommen, muss die Logik Ihres Programms möglicherweise etwas bearbeitet werden. Wie haben Sie dann überhaupt versucht, eine Zeichenfolge mit einem numerischen Vektor zu multiplizieren?
quelle
Um vorhandene Methoden zusammenzufassen / zu bewerten:
(Ich bin mit dieser Frage hierher gekommen )
Code
quelle
float('nan'), 'nan', '123.45', '42', '42a', '0x8', '0xa'
, hinzufügenmath.isnan
Wahrscheinlich ist es besser, es einfach umgekehrt zu machen: Sie überprüfen, ob es sich um einen Vektor handelt. Wenn dies der Fall ist, erstellen Sie ein Punktprodukt und in allen anderen Fällen versuchen Sie eine skalare Multiplikation.
Das Überprüfen des Vektors ist einfach, da er von Ihrem Vektorklassentyp sein sollte (oder von ihm geerbt wurde). Sie können auch einfach versuchen, zuerst ein Punktprodukt zu erstellen. Wenn dies fehlschlägt (= es war nicht wirklich ein Vektor), können Sie auf die Skalarmultiplikation zurückgreifen.
quelle
Nur um etwas hinzuzufügen. Vielleicht können wir eine Kombination aus isinstance und isdigit wie folgt verwenden, um herauszufinden, ob ein Wert eine Zahl ist (int, float usw.)
wenn isinstance (num1, int) oder isinstance (num1, float) oder num1.isdigit ():
quelle
Für die hypothetische Vektorklasse:
Angenommen, es
v
ist ein Vektor, und wir multiplizieren ihn mitx
. Wenn es sinnvoll ist, jede Komponente vonv
mit zu multiplizierenx
, haben wir das wahrscheinlich so gemeint, also versuchen Sie es zuerst. Wenn nicht, können wir vielleicht punktieren? Ansonsten ist es ein Tippfehler.BEARBEITEN - der folgende Code funktioniert nicht, weil
2*[0]==[0,0]
statt aTypeError
. Ich lasse es, weil es kommentiert wurde.quelle
x
ein Vektor dann[comp * x for comp in self]
nachgeben das äußere Produkt vonx
einv
. Dies ist ein Tensor vom Rang 2, kein Skalar.comp*x
skaliertx
durchcomp
, war ich davon aus, dass es eine Typeerror erhöhen würde. Leider wird es tatsächlich malx
mit sich selbst verkettencomp
. Hoppla.x
es sich um einen Vektor handelt, sollte er eine__rmul__
Methode (__rmul__ = __mul__
) haben,comp * x
diex
auf die gleiche Weise skaliert , wiex * comp
es anscheinend beabsichtigt ist.Ich hatte ein ähnliches Problem bei der Implementierung einer Art Vektorklasse. Eine Möglichkeit, nach einer Zahl zu suchen, besteht darin, sie einfach in eine zu konvertieren, dh mit
Dies sollte Fälle ablehnen, in denen x nicht in eine Zahl konvertiert werden kann. kann aber auch andere Arten von zahlenähnlichen Strukturen ablehnen, die gültig sein könnten, beispielsweise komplexe Zahlen.
quelle
Wenn Sie je nach Argumenttyp (en) unterschiedliche Methoden aufrufen möchten, prüfen Sie
multipledispatch
.Leider können wir (meines Wissens) nicht schreiben,
@dispatch(Vector)
da wir den Typ noch definierenVector
, sodass der Typname noch nicht definiert ist. Stattdessen verwende ich den Basistyplist
, mit dem Sie sogar das Punktprodukt von aVector
und a finden könnenlist
.quelle
Kurzer und einfacher Weg:
Ausgabe :
Wenn das Objekt eine Zeichenfolge ist, wird 'False' zurückgegeben:
Ausgabe :
quelle
Sie haben ein Datenelement, sagen Sie,
rec_day
dass beim Schreiben in eine Datei einfloat
. Aber während der Programmbearbeitung kann es entwederfloat
,int
oderstr
Typ (derstr
verwendet wird , wenn ein neuer Datensatz zu initialisieren und enthält einen Dummy - Flag - Wert).Sie können dann überprüfen, ob Sie eine Nummer mit dieser haben
Ich habe ein Python-Programm auf diese Weise strukturiert und einfach einen 'Wartungs-Patch' eingefügt, der dies als numerische Prüfung verwendet. Ist es der pythonische Weg? Höchstwahrscheinlich nicht, seit ich in COBOL programmiert habe.
quelle
Sie können die Funktion isdigit () verwenden.
quelle