Określić typ obiektu?
Czy istnieje prosty sposób na określenie, czy zmienna jest listą, słownikiem, czy czymś innym? Dostaję z powrotem obiekt, który może być albo typu i muszę być w stanie odróżnić.
9 answers
Aby uzyskać typ obiektu, możesz użyć wbudowanego type()
funkcja. Przekazanie obiektu jako jedynego parametru zwróci obiekt typu tego obiektu:
>>> type([]) is list
True
>>> type({}) is dict
True
>>> type('') is str
True
>>> type(0) is int
True
>>> type({})
<type 'dict'>
>>> type([])
<type 'list'>
To oczywiście działa również dla niestandardowych typów:
>>> class Test1 (object):
pass
>>> class Test2 (Test1):
pass
>>> a = Test1()
>>> b = Test2()
>>> type(a) is Test1
True
>>> type(b) is Test2
True
Zauważ, że type()
zwróci tylko bezpośredni typ obiektu, ale nie będzie w stanie powiedzieć ci o dziedziczeniu typu.
>>> type(b) is Test1
False
Aby to pokryć, należy użyć isinstance
funkcja. To oczywiście działa również na typy wbudowane:
>>> isinstance(b, Test1)
True
>>> isinstance(b, Test2)
True
>>> isinstance(a, Test1)
True
>>> isinstance(a, Test2)
False
>>> isinstance([], list)
True
>>> isinstance({}, dict)
True
isinstance()
jest zwykle preferowanym sposobem zapewnienia typu obiektu, ponieważ akceptuje również typy pochodne. Jeśli więc nie potrzebujesz obiektu typu (z jakiegokolwiek powodu), użycie isinstance()
jest preferowane zamiast type()
.
Drugi parametr isinstance()
również akceptuje krotkę typów, więc możliwe jest sprawdzenie wielu typów naraz. isinstance
zwróci true, jeśli obiekt jest dowolnego z tych typów:
>>> isinstance([], (tuple, list, set))
True
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-19 15:17:28
Możesz to zrobić używając type()
:
>>> a = []
>>> type(a)
<type 'list'>
>>> f = ()
>>> type(f)
<type 'tuple'>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-08 21:39:17
Może być bardziej Pythoniczne użycie try
...except
blok. W ten sposób, jeśli masz klasę, która kwacze jak lista, lub kwacze jak dict, będzie zachowywać się poprawnie niezależnie od tego, jaki jest jej typ naprawdę.
Aby wyjaśnić, preferowaną metodą "rozróżniania" między typami zmiennych jest coś o nazwie typowanie kaczki : tak długo, jak metody (i typy zwrotne), na które odpowiada zmienna, są tym, czego oczekuje Twój podprogram, traktuj to tak, jak oczekujesz tak będzie. Na przykład, jeśli masz klasę, która przeciąża operatory nawiasów za pomocą getattr
i setattr
, ale używa jakiegoś śmiesznego wewnętrznego schematu, byłoby właściwe, aby zachowywała się jak słownik, jeśli to próbuje naśladować.
Inny problem z sprawdzaniem type(A) is type(B)
polega na tym, że jeśli A
jest podklasą B
, to ewaluuje do false
kiedy, programowo, masz nadzieję, że będzie to true
. Jeśli obiekt jest podklasą listy, powinien działać jak lista: sprawdzanie typu jako przedstawione w drugiej odpowiedzi zapobiegną temu. (isinstance
będzie działać, jednak).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-09 16:56:49
Na instancjach obiektu masz również:
__class__
Atrybut. Oto przykład zaczerpnięty z Pythona 3.3 console
>>> str = "str"
>>> str.__class__
<class 'str'>
>>> i = 2
>>> i.__class__
<class 'int'>
>>> class Test():
... pass
...
>>> a = Test()
>>> a.__class__
<class '__main__.Test'>
Uważaj na to w Pythonie 3.x i w klasach nowego stylu (dostępnych opcjonalnie od Pythona 2.6) klasy i typy zostały połączone, co może czasami prowadzić do nieoczekiwanych rezultatów. Głównie z tego powodu moim ulubionym sposobem testowania typów / klas jest wbudowana funkcja isinstance .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-26 21:38:42
Określ typ obiektu Pythona
Określ typ obiektu za pomocą type
>>> obj = object()
>>> type(obj)
<class 'object'>
Chociaż to działa, unikaj podwójnych atrybutów podkreślenia, takich jak __class__
- nie są one semantycznie publiczne i, choć być może nie w tym przypadku, wbudowane funkcje zwykle mają lepsze zachowanie.
>>> obj.__class__ # avoid this!
<class 'object'>
Sprawdzanie typu
Czy istnieje prosty sposób na określenie, czy zmienna jest listą, słownikiem, czy czymś innym? Odzyskuję obiekt, który może być każdy typ i ja musimy być w stanie odróżnić.
Cóż to jest inne pytanie, nie używaj typu - use isinstance
:
def foo(obj):
"""given a string with items separated by spaces,
or a list or tuple,
do something sensible
"""
if isinstance(obj, str):
obj = str.split()
return _foo_handles_only_lists_or_tuples(obj)
Obejmuje to przypadek, w którym użytkownik może robić coś mądrego lub sensownego poprzez podklasowanie str
- zgodnie z zasadą substytucji Liskov, chcesz być w stanie używać podklasowych instancji bez łamania kodu - i isinstance
to wspiera.
Użyj Abstrakcji
Jeszcze lepiej, możesz poszukać specyficzna abstrakcyjna klasa bazowa z collections
lub numbers
:
from collections import Iterable
from numbers import Number
def bar(obj):
"""does something sensible with an iterable of numbers,
or just one number
"""
if isinstance(obj, Number): # make it a 1-tuple
obj = (obj,)
if not isinstance(obj, Iterable):
raise TypeError('obj must be either a number or iterable of numbers')
return _bar_sensible_with_iterable(obj)
Lub po prostu nie sprawdzaj jawnie typu
Lub, być może najlepiej, używaj pisania kaczką i nie wpisuj jawnie-sprawdź swój kod. Duck-typing obsługuje Podstawienie Liskowa z większą elegancją i mniejszą szczegółowością.
def baz(obj):
"""given an obj, a dict (or anything with an .items method)
do something sensible with each key-value pair
"""
for key, value in obj.items():
_baz_something_sensible(key, value)
Podsumowanie
- Użyj
type
, aby uzyskać klasę instancji. - użyj
isinstance
, aby wyraźnie sprawdzić rzeczywiste podklasy lub zarejestrowane abstrakcje. - i po prostu unikaj sprawdzania typu, gdzie ma to sens.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-14 21:12:16
Możesz użyć type()
lub isinstance()
.
>>> type([]) is list
True
Ostrzegam, że możesz zablokować list
lub dowolny inny typ, przypisując zmienną w bieżącym zakresie o tej samej nazwie.
>>> the_d = {}
>>> t = lambda x: "aight" if type(x) is dict else "NOPE"
>>> t(the_d) 'aight'
>>> dict = "dude."
>>> t(the_d) 'NOPE'
Powyżej widzimy, że {[7] } zostaje przypisany do ciągu, dlatego test:
type({}) is dict
...zawodzi.
Aby obejść to i używać type()
bardziej ostrożnie:
>>> import __builtin__
>>> the_d = {}
>>> type({}) is dict
True
>>> dict =""
>>> type({}) is dict
False
>>> type({}) is __builtin__.dict
True
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-31 21:57:27
Chociaż pytania są dość stare, natknąłem się na to, gdy sam znalazłem odpowiedni sposób i myślę, że nadal wymaga wyjaśnienia, przynajmniej dla Pythona 2.x (nie sprawdzałem Pythona 3, ale ponieważ pojawia się problem z klasycznymi klasami, które zniknęły 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 nie używania isinstance są w porządku w wielu komentarzach i odpowiedziach, ale nie zajmuję się tymi obawami.
Głównym problemem w podejściu type()
jest to, że nie działa poprawnie z instancjami starego stylu :
class One:
pass
class Two:
pass
o = One()
t = Two()
o_type = type(o)
t_type = type(t)
print "Are o and t instances of the same class?", o_type is t_type
Wykonanie tego fragmentu dałoby:
Are o and t instances of the same class? True
Co, jak sądzę, nie jest tym, czego większość ludzi by się spodziewała.
Podejście __class__
jest najbardziej zbliżone do poprawności, ale nie zadziała w jednym kluczowym przypadku: gdy przekazywany obiekt jest klasą w starym stylu (nie instancją!), ponieważ obiekty te nie posiadają takiego atrybutu.
Jest to najmniejszy fragment kodu, jaki mogłem wymyślić, który spełnia tak uzasadnione pytanie w spójny sposób:
#!/usr/bin/env python
from types import ClassType
#we adopt the null object pattern in the (unlikely) case
#that __class__ is None for some strange reason
_NO_CLASS=object()
def get_object_type(obj):
obj_type = getattr(obj, "__class__", _NO_CLASS)
if obj_type is not _NO_CLASS:
return obj_type
# AFAIK the only situation where this happens is an old-style class
obj_type = type(obj)
if obj_type is not ClassType:
raise ValueError("Could not determine object '{}' type.".format(obj_type))
return obj_type
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-17 08:35:20
Na marginesie poprzednich odpowiedzi warto wspomnieć o istnieniu collections.abc
który zawiera kilka abstrakcyjnych klas bazowych (ABC), które uzupełniają typowanie kaczek.
Na przykład, zamiast jawnie sprawdzać, czy coś jest listą z:
isinstance(my_obj, list)
Możesz, jeśli interesuje Cię tylko to, czy obiekt, który posiadasz pozwala na uzyskanie przedmiotów, użyć collections.abc.Sequence
:
from collections.abc import Sequence
isinstance(my_obj, Sequence)
Jeśli interesują Cię obiekty, które pozwalają na uzyskanie, ustawienie i usuwanie elementów (np. mutowalnych sekwencji), należy wybrać collections.abc.MutableSequence
.
Zdefiniowano tam wiele innych ABC Mapping
dla obiektów, które mogą być używane jako mapy, Iterable
, Callable
, i tak dalej. Pełna lista tych wszystkich znajduje się w dokumentacji collections.abc
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-07 15:50:37
Bądź ostrożny używając isinstance
isinstance(True, bool)
True
>>> isinstance(True, int)
True
Ale Typ
type(True) == bool
True
>>> type(True) == int
False
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-14 11:22:11