Biorąc pod uwagę dowolny obiekt Pythona, jaki jest najlepszy sposób określenia, czy jest to liczba? Tutaj is
jest zdefiniowany jako acts like a number in certain circumstances
.
Na przykład, powiedzmy, że piszesz klasę wektorową. Jeśli masz inny wektor, chcesz znaleźć iloczyn skalarny. Jeśli masz skalar, chcesz przeskalować cały wektor.
Sprawdzanie, czy coś jest int
, float
, long
, bool
jest irytujące i nie obejmuje zdefiniowanych przez użytkownika obiektów, które mogą działać jak numery. Ale __mul__
na przykład sprawdzenie, czy nie jest wystarczająco dobre, ponieważ klasa wektora, którą właśnie opisałem, zdefiniowałaby __mul__
, ale nie byłaby to liczba, której chcę.
isinstance(value, Number) and type(value) != bool
Chcesz sprawdzić, czy jakiś obiekt
Jeśli używasz Pythona 2.5 lub starszego, jedynym prawdziwym sposobem jest sprawdzenie niektórych z tych „pewnych okoliczności” i zobaczenie.
W wersji 2.6 lub nowszej można używać
isinstance
z liczbami Numer - abstrakcyjna klasa bazowa (ABC), która istnieje dokładnie w tym celu (wcollections
module istnieje o wiele więcej ABC dla różnych form kolekcji / kontenerów, ponownie zaczynając od 2.6; oraz również tylko w tych wydaniach możesz łatwo dodać własne abstrakcyjne klasy bazowe, jeśli zajdzie taka potrzeba).Bacha do 2.5 i wcześniejszych, „można dodać
0
i nie jest iterowalne” może być w niektórych przypadkach dobrą definicją. Ale naprawdę musisz zadać sobie pytanie, co to jest, że pytasz, że to, co chcesz uznać za „liczbę”, musi zdecydowanie być w stanie zrobić , a czego absolutnie nie może zrobić - i sprawdzić.Może to być również potrzebne w wersji 2.6 lub nowszej, być może w celu tworzenia własnych rejestracji w celu dodania typów, na których Ci zależy, a które nie zostały jeszcze zarejestrowane
numbers.Numbers
- jeśli chcesz wykluczyć niektóre typy, które twierdzą, że są numerami, ale ty po prostu nie mogę sobie z tym poradzić, to wymaga jeszcze większej ostrożności, ponieważ ABC nie maunregister
metody [[na przykład możesz stworzyć własne ABCWeirdNum
i zarejestrować tam wszystkie takie dziwne dla ciebie typy, a następnie najpierw sprawdzić, czyisinstance
wyskoczysz, zanim przejdziesz dalej sprawdzanieisinstance
normalności,numbers.Number
aby kontynuować pomyślnie.BTW, jeśli i kiedy chcesz sprawdzić, czy
x
możesz lub nie możesz coś zrobić, generalnie musisz spróbować czegoś takiego:Obecność
__add__
per se nie mówi nic użytecznego, ponieważ np. Wszystkie sekwencje mają je w celu połączenia z innymi sekwencjami. To sprawdzenie jest równoważne definicji „liczba jest czymś takim, że sekwencja takich rzeczy jest prawidłowym pojedynczym argumentem funkcji wbudowanejsum
”. Całkowicie dziwne typy (np. Takie, które podnoszą „zły” wyjątek po zsumowaniu do 0, takie jak, powiedzmy, aZeroDivisionError
lubValueError
& c) będą propagować wyjątek, ale to jest w porządku, daj użytkownikowi jak najszybciej wiedzieć, że takie szalone typy są po prostu nie do przyjęcia w dobrym firma;-); ale „wektor”, który można podsumować jako skalar (standardowa biblioteka Pythona go nie ma, ale oczywiście są popularne jako rozszerzenia innych firm) również dałby tutaj zły wynik, więc (np.opcja „nie może być iterowalna” (np. sprawdź, czyiter(x)
podbijaTypeError
, lub na obecność specjalnej metody__iter__
- jeśli jesteś w 2.5 lub wcześniej i potrzebujesz własnych kontroli).Krótkie spojrzenie na takie komplikacje może wystarczyć, aby zmotywować Cię do polegania na abstrakcyjnych klasach bazowych, gdy tylko jest to możliwe ... ;-).
źródło
To dobry przykład, w którym wyjątki naprawdę świecą. Po prostu zrób to, co zrobiłbyś z typami liczbowymi i wyłap
TypeError
wszystkie inne.Ale oczywiście sprawdza tylko, czy operacja działa , a nie czy ma sens ! Jedynym realnym rozwiązaniem jest to, aby nigdy nie mieszać typów i zawsze dokładnie wiedzieć, do jakiej typeklasy należą twoje wartości.
źródło
isinstance
może być faktycznie przydatna w wielu przypadkach (== "sprawdź to ma sens", jak również formalne zastosowanie operacji). Trudna zmiana dla osób od dawna korzystających wyłącznie z języka Python, ale bardzo ważny subtelny trend w filozofii Pythona, którego zignorowanie byłoby poważnym błędem.collections.Sequence
i przyjaciół). Ale afaik, nie ma takich klas dla liczb, wektorów ani żadnych innych obiektów matematycznych.Pomnóż obiekt przez zero. Dowolna liczba razy zero daje zero. Każdy inny wynik oznacza, że obiekt nie jest liczbą (łącznie z wyjątkami)
W ten sposób użycie isNumber da następujący wynik:
Wynik:
Prawdopodobnie istnieją na świecie obiekty nieliczbowe, które
__mul__
po pomnożeniu przez zero definiują zwracanie zera, ale jest to skrajny wyjątek. To rozwiązanie powinno obejmować cały normalny i rozsądny kod, który generujesz / szyfrujesz.przykład numpy.array:
wynik:
źródło
True * 0 == 0
int
więc moja funkcja poprawnie powie, że wartości logiczne to liczby.Aby przeformułować swoje pytanie, próbujesz określić, czy coś jest zbiorem czy pojedynczą wartością. Próba porównania, czy coś jest wektorem, czy liczbą, jest porównaniem jabłek z pomarańczami - mogę mieć wektor ciągów lub liczb i mogę mieć pojedynczy ciąg lub pojedynczą liczbę. Interesuje Cię, ile ich masz (1 lub więcej) , a nie jaki typ faktycznie posiadasz.
moim rozwiązaniem tego problemu jest sprawdzenie, czy dane wejściowe są pojedynczą wartością, czy kolekcją, sprawdzając obecność
__len__
. Na przykład:Lub, jeśli chodzi o podejście do pisania kaczego, możesz najpierw wypróbować iterację
foo
:Ostatecznie łatwiej jest sprawdzić, czy coś jest podobne do wektora, niż sprawdzić, czy coś jest podobne do skalarnego. Jeśli przechodzą przez Ciebie wartości innego typu (np. Łańcuch, liczba itp.), Logika twojego programu może wymagać trochę pracy - w jaki sposób w pierwszej kolejności próbowałeś pomnożyć ciąg przez wektor numeryczny?
źródło
Podsumowanie / ocena istniejących metod:
(Przyszedłem tutaj przez to pytanie )
Kod
źródło
float('nan'), 'nan', '123.45', '42', '42a', '0x8', '0xa'
dodajmath.isnan
Prawdopodobnie lepiej zrobić to na odwrót: sprawdzasz, czy to wektor. Jeśli tak, robisz iloczyn skalarny, a we wszystkich innych przypadkach próbujesz mnożyć przez skalar.
Sprawdzenie wektora jest łatwe, ponieważ powinien on należeć do typu Twojej klasy wektorów (lub być z niego dziedziczony). Możesz także spróbować najpierw wykonać iloczyn skalarny, a jeśli to się nie powiedzie (= tak naprawdę nie był to wektor), wtedy powróć do mnożenia przez skalar.
źródło
Po prostu dodać. Być może możemy użyć kombinacji isinstance i isdigit w następujący sposób, aby sprawdzić, czy wartość jest liczbą (int, float itp.)
if isinstance (num1, int) or isinstance (num1, float) lub num1.isdigit ():
źródło
Dla hipotetycznej klasy wektorów:
Załóżmy, że
v
jest to wektor i mnożymy go przezx
. Jeśli pomnożenie każdego składnikav
przez przez ma sensx
, prawdopodobnie mieliśmy na myśli to, więc spróbuj najpierw. Jeśli nie, może możemy kropkować? W przeciwnym razie jest to błąd typu.EDYCJA - poniższy kod nie działa, ponieważ
2*[0]==[0,0]
zamiast podnosićTypeError
. Zostawiam to, ponieważ zostało skomentowane.źródło
x
jest wektorem, to[comp * x for comp in self]
da iloczyn zewnętrznyx
anv
. To jest tensor rangi 2, a nie skalar.comp*x
będą skalowanex
przezcomp
, byłem przy założeniu, że będzie podnieść TypeError. Niestety, w rzeczywistości połączy sięx
ze sobącomp
razy. Ups.x
jest wektorem, to powinien mieć__rmul__
metodę method (__rmul__ = __mul__
), któracomp * x
powinna być skalowanax
w ten sam sposób, w jakix * comp
jest to najwyraźniej zamierzone.Podobny problem miałem przy implementacji pewnego rodzaju klasy wektorowej. Jednym ze sposobów sprawdzenia liczby jest po prostu przekonwertowanie na jeden, czyli użycie
Powinno to odrzucić przypadki, w których x nie może zostać zamienione na liczbę; ale może również odrzucić inne rodzaje struktur podobnych do liczb, które mogą być prawidłowe, na przykład liczby zespolone.
źródło
Jeśli chcesz wywołać różne metody w zależności od typu argumentów, spójrz na
multipledispatch
.Niestety (o ile mi wiadomo) nie możemy pisać,
@dispatch(Vector)
ponieważ wciąż definiujemy typVector
, więc nazwa typu nie jest jeszcze zdefiniowana. Zamiast tego używam typu podstawowegolist
, który pozwala nawet znaleźć iloczyn skalarny aVector
i alist
.źródło
Krótki i prosty sposób:
Wynik :
Jeśli obiekt jest ciągiem znaków, zostanie zwrócony „False”:
Wynik :
źródło
Masz element danych, powiedz,
rec_day
że po zapisaniu do pliku będzie tofloat
. Ale podczas przetwarzania programu może to być albofloat
,int
albostr
typ (str
jest używany podczas inicjowania nowego rekordu i zawiera fikcyjną wartość flagi).Następnie możesz sprawdzić, czy masz numer z tym
Skonstruowałem program w Pythonie w ten sposób i po prostu umieściłem `` poprawkę konserwacyjną '', używając tego jako kontroli numerycznej. Czy to sposób w Pythonie? Najprawdopodobniej nie, odkąd programowałem w języku COBOL.
źródło
Możesz użyć funkcji isdigit ().
źródło