Czy istnieje prosty sposób ustalenia, czy zmienna jest listą, słownikiem czy czymś innym? Otrzymuję z powrotem obiekt, który może być dowolnego typu i muszę być w stanie odróżnić.
python
dictionary
types
typeof
Justin Ethier
źródło
źródło
try
który nie pomaga. Na przykład, jeśli wiesz, że użytkownik może przekazać ciąg lub tablicę, oba są w stanie indeksować, ale ten indeks oznacza coś zupełnie innego. Po prostu poleganie na try-catch w tych przypadkach zawiedzie w nieoczekiwany i dziwny sposób. Jednym rozwiązaniem jest stworzenie osobnej metody, innym sposobem dodania małego sprawdzania typu. Osobiście wolę zachowanie polimorficzne niż wiele metod, które robią prawie to samo ... ale to tylko ja :)Odpowiedzi:
Istnieją dwie wbudowane funkcje, które pomagają zidentyfikować typ obiektu. Można użyć
type()
, jeśli potrzebujesz dokładny typ obiektu, aisinstance()
do sprawdzenia typ obiektu, przed czymś. Zazwyczaj chcesz używać przezisistance()
większość czasu, ponieważ jest bardzo solidny i obsługuje dziedziczenie typu.Aby uzyskać rzeczywisty typ obiektu, użyj wbudowanej
type()
funkcji. Przekazanie obiektu jako jedynego parametru zwróci obiekt typu tego obiektu:To oczywiście działa również w przypadku niestandardowych typów:
Zauważ, że
type()
zwróci tylko bezpośredni typ obiektu, ale nie będzie w stanie powiedzieć ci o dziedziczeniu typu.Aby to pokryć, powinieneś użyć
isinstance
funkcji. To oczywiście działa również w przypadku typów wbudowanych:isinstance()
jest zwykle preferowanym sposobem zapewnienia typu obiektu, ponieważ akceptuje on także typy pochodne. Tak więc, chyba że faktycznie potrzebujesz obiektu typu (z jakiegokolwiek powodu), użycieisinstance()
jest lepsze niżtype()
.Drugi parametr
isinstance()
akceptuje również krotkę typów, więc możliwe jest sprawdzenie wielu typów jednocześnie.isinstance
zwróci wówczas wartość true, jeśli obiekt jest dowolnego z tych typów:źródło
is
zamiast==
jak typy są samotnymiisinstance
jest preferowaną formą byle jak, więc nie==
bądźis
muszą być użyte.type
jest najlepsza odpowiedź. Są chwile, kiedyisinstance
najlepsza odpowiedź, a czasami pisanie kaczki jest najlepszą odpowiedzią. Ważne jest, aby znać wszystkie opcje, abyś mógł wybrać bardziej odpowiedni dla danej sytuacji.type(foo) is SomeType
byłoby lepiej niżisinstance(foo, SomeType)
.isinstance
przypadku użycia (sprawdzanie zakresu typów), a także z jako czystą składnię, która ma tę wielką zaletę, że można przechwytywać podklasy. ktoś, kto go używaOrderedDict
, nienawidzi twojego kodu do niepowodzenia, ponieważ akceptuje on tylko czyste dyktanda.Możesz to zrobić za pomocą
type()
:źródło
Używanie
try
...except
bloku może być bardziej Pythoniczne . W ten sposób, jeśli masz klasę, która znachorów jak liście lub znachorów jak dict, będzie zachowywać się poprawnie niezależnie od jej rodzaju naprawdę jest.Aby wyjaśnić, preferowaną metodą „odróżniania” typów zmiennych jest coś, co nazywa się pisaniem kaczym : o ile metody (i typy zwracane), na które reaguje zmienna, są zgodne z oczekiwaniami podprogramu, należy traktować to tak, jak się tego oczekuje być. Na przykład, jeśli masz klasę, która przeciąża operatorów nawiasów
getattr
isetattr
, ale używa jakiegoś śmiesznego schematu wewnętrznego, byłoby odpowiednie, aby zachowywał się jak słownik, jeśli to właśnie próbuje naśladować.Innym problemem związanym ze
type(A) is type(B)
sprawdzaniem jest to, że jeśliA
jest podklasąB
, ocenia,false
kiedy programowo można się spodziewaćtrue
. Jeśli obiekt jest podklasą listy, powinien działać jak lista: sprawdzenie typu przedstawionego w drugiej odpowiedzi zapobiegnie temu. (isinstance
będzie jednak działać).źródło
try
...except
to dobre rozwiązanie, gdy chcesz poradzić sobie z błędami, ale nie przy podejmowaniu decyzji dotyczących zachowania na podstawie typu.Na instancjach obiektu masz również:
atrybut. Oto próbka pobrana z konsoli Python 3.3
Uwaga: w Pythonie 3.xi klasach New Style (dostępne opcjonalnie z Pythona 2.6) klasy i typy zostały scalone, co może czasem prowadzić do nieoczekiwanych rezultatów. Głównie z tego powodu moim ulubionym sposobem testowania typów / klas jest wbudowana funkcja isinstance .
źródło
__class__
działa głównie w Pythonie 2.x, jedynymi obiektami w Pythonie, które nie mają__class__
atrybutu, są klasy AFAIK w starym stylu. Nawiasem mówiąc, nie rozumiem twojego problemu z Python 3 - w takiej wersji tylko każdy obiekt ma__class__
atrybut wskazujący odpowiednią klasę.Określ typ obiektu Python
Określ typ obiektu za pomocą
type
Chociaż działa, unikaj podwójnych atrybutów podkreślenia, takich jak
__class__
- nie są one semantycznie publiczne, i chociaż być może nie w tym przypadku, wbudowane funkcje zwykle działają lepiej.sprawdzanie typu
Cóż, to inne pytanie, nie używaj tekstu - użyj
isinstance
:Obejmuje to przypadek, w którym użytkownik może robić coś sprytnego lub sensownego przez podklasowanie
str
- zgodnie z zasadą substytucji Liskova, chcesz mieć możliwość korzystania z instancji podklasy bez łamania kodu - iisinstance
obsługuje to.Użyj abstrakcji
Co więcej, możesz poszukać konkretnej abstrakcyjnej klasy bazowej z
collections
lubnumbers
:Lub po prostu nie zaznaczaj wyraźnie typu
Lub, co najlepsze, użyj kaczych pism i nie sprawdzaj bezpośrednio swojego kodu. Pisanie na kaczkach obsługuje substytucję Liskova z większą elegancją i mniej gadatliwością.
Wniosek
type
do uzyskania klasy instancji.isinstance
do jawnego sprawdzania rzeczywistych podklas lub zarejestrowanych abstrakcji.źródło
try
/except
zamiast jawnego sprawdzania.Możesz użyć
type()
lubisinstance()
.Ostrzegamy, że możesz zablokować
list
lub użyć dowolnego innego typu, przypisując zmienną w bieżącym zakresie o tej samej nazwie.Powyżej widzimy, że
dict
zostaje on ponownie przypisany do łańcucha, dlatego test:... zawodzi.
Aby obejść ten problem i
type()
zachować ostrożność:źródło
dict
ciąg również nie powiedzie się w przypadku wielu innych kodów, takich jakdict([("key1", "value1"), ("key2", "value2")])
. Odpowiedzią na tego rodzaju problemy jest „Więc nie rób tego” . Nie cień nazw wbudowanych typów i oczekuj, że wszystko będzie działać poprawnie.Chociaż pytania są dość stare, natknąłem się na to, jednocześnie sam znajdując właściwy sposób, i myślę, że nadal wymaga wyjaśnienia, przynajmniej w przypadku Python 2.x (nie sprawdziłem w Python 3, ale ponieważ problem pojawia się w klasycznych klasach które zostały usunięte w takiej wersji, prawdopodobnie nie ma to znaczenia).
Tutaj próbuję odpowiedzieć na pytanie tytułu: jak mogę określić typ dowolnego obiektu ? Inne sugestie dotyczące używania lub nieużywania isinstance są w porządku w wielu komentarzach i odpowiedziach, ale nie odpowiadam na te obawy.
Głównym problemem związanym z tym
type()
podejściem jest to, że nie działa ono poprawnie w instancjach w starym stylu :Wykonanie tego fragmentu kodu dałoby:
Twierdzę, że nie jest to, czego większość ludzi by się spodziewała.
__class__
Podejście jest najbardziej blisko poprawności, ale to nie będzie działać w jednej kluczowej sprawie: gdy przeszedł w obiekcie jest starym stylu klasy (! Nie instancją), ponieważ obiekty te nie mają takiego atrybutu.Jest to najmniejszy fragment kodu, który mógłbym wymyślić, który spełnia takie uzasadnione pytanie w spójny sposób:
źródło
bądź ostrożny używając isinstance
ale wpisz
źródło
Oprócz poprzednich odpowiedzi, warto wspomnieć o istnieniu tego,
collections.abc
który zawiera kilka abstrakcyjnych klas bazowych (ABC), które uzupełniają pisanie kaczek.Na przykład zamiast jawnego sprawdzania, czy coś jest listą z:
możesz, jeśli chcesz tylko sprawdzić, czy posiadany obiekt pozwala na zdobywanie przedmiotów, użyj
collections.abc.Sequence
:jeśli jesteś bardzo zainteresowany obiektami, które umożliwiają pobieranie, ustawianie i usuwanie elementów (tj. sekwencje zmienne ), wybierz
collections.abc.MutableSequence
.Wiele innych ABC zdefiniowane są tam
Mapping
dla obiektów, które mogą być stosowane jako mapy,Iterable
,Callable
, et cetera. Pełna lista tych wszystkich znajduje się w dokumentacji dlacollections.abc
.źródło
Ogólnie rzecz biorąc, możesz wyodrębnić ciąg z obiektu o nazwie klasy,
i używając go do porównania,
źródło
W wielu praktycznych przypadkach zamiast używać
type
lubisinstance
można również użyć@functools.singledispatch
, który służy do definiowania funkcji ogólnych ( funkcja złożona z wielu funkcji realizujących tę samą operację dla różnych typów ).Innymi słowy, powinieneś go użyć, gdy masz kod podobny do następującego:
Oto mały przykład tego, jak to działa:
Dodatkowo możemy użyć klas abstrakcyjnych, aby objąć kilka typów jednocześnie:
źródło
type()
jest lepszym rozwiązaniem niżisinstance()
, szczególnie dlabooleans
:True
iFalse
to tylko słowa kluczowe, to znaczy, że1
i0
w Pythonie. A zatem,i
oba wracają
True
. Oba booleany są wystąpieniem liczby całkowitej.type()
jest jednak bardziej sprytny:zwraca
False
.źródło