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ć.

 1441
Author: martineau, 2010-02-09

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
 1658
Author: poke,
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'>
 146
Author: inkedmn,
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).

 38
Author: Seth Johnson,
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 .

 32
Author: Lorenzo Persichetti,
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.
 15
Author: Aaron Hall,
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
 11
Author: deed02392,
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
 4
Author: Alan Franzoni,
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.

 3
Author: Jim Fasarakis Hilliard,
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
 3
Author: Mr.Green,
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