Determinar o tipo de objecto?
Existe uma maneira simples de determinar se uma variável é uma lista, dicionário, ou algo mais? Estou recebendo um objeto de volta que pode ser qualquer tipo e eu preciso ser capaz de dizer a diferença.
9 answers
Para obter o tipo de objeto, você pode usar o embutido type()
função. Passando um objeto como o único parâmetro irá retornar o tipo de objeto desse objeto:
>>> type([]) is list
True
>>> type({}) is dict
True
>>> type('') is str
True
>>> type(0) is int
True
>>> type({})
<type 'dict'>
>>> type([])
<type 'list'>
Isto também funciona para tipos personalizados:
>>> class Test1 (object):
pass
>>> class Test2 (Test1):
pass
>>> a = Test1()
>>> b = Test2()
>>> type(a) is Test1
True
>>> type(b) is Test2
True
Note que type()
só irá devolver o tipo imediato do objecto, mas não será capaz de lhe falar sobre herança tipo.
>>> type(b) is Test1
False
Para cobrir isso, deve usar o isinstance
função. É claro que isto também funciona para tipos incorporados:
>>> isinstance(b, Test1)
True
>>> isinstance(b, Test2)
True
>>> isinstance(a, Test1)
True
>>> isinstance(a, Test2)
False
>>> isinstance([], list)
True
>>> isinstance({}, dict)
True
isinstance()
é geralmente a maneira preferida de garantir o tipo de um objeto porque ele também aceitará tipos derivados. Então, a menos que você realmente precise do objeto tipo (por qualquer razão), usar isinstance()
é preferido sobre type()
.
O segundo parâmetro de {[8] } também aceita uma tupla de tipos, por isso é possível verificar vários tipos de uma vez. isinstance
então retornará verdadeiro, se o objeto for de algum desses tipos:
>>> isinstance([], (tuple, list, set))
True
Podes fazer isso usando type()
:
>>> a = []
>>> type(a)
<type 'list'>
>>> f = ()
>>> type(f)
<type 'tuple'>
Pode ser mais Pythonic usar um {[[0]}...Bloco. Dessa forma, se você tiver uma classe que grasna como uma lista, ou grasna como uma dict, ela se comportará corretamente independentemente do que seu tipo realmente é.
Para esclarecer, o método preferido de "dizer a diferença" entre os tipos variáveis é com algo chamado duck typing : desde que os métodos (e tipos de retorno) a que uma variável responde sejam o que a sua sub-rotina espera, trate - o como você espera que seja. Por exemplo, se você tem uma classe que sobrecarrega os operadores de suporte com {[[2]} e setattr
, mas usa algum esquema interno engraçado, seria apropriado que ele se comportasse como um dicionário, se é isso que ele está tentando imitar.
O outro problema com a verificação de type(A) is type(B)
é que se A
é uma subclasse de B
, ele avalia para false
quando, programaticamente, você esperaria que fosse true
. Se um objeto é uma subclasse de uma lista, ele deve funcionar como uma lista: o tipo apresentado na outra resposta evitará isso. ([[9]} funcionará, no entanto).
Em instâncias de objeto você também tem o:
__class__
Atributo. Aqui está uma amostra retirada da consola do Python 3.3
>>> str = "str"
>>> str.__class__
<class 'str'>
>>> i = 2
>>> i.__class__
<class 'int'>
>>> class Test():
... pass
...
>>> a = Test()
>>> a.__class__
<class '__main__.Test'>
Cuidado com isso no python 3.as classes x e New-Style (aviable opcionalmente a partir do Python 2.6) foram fundidas e isso pode levar a resultados inesperados. Principalmente por esta razão, a minha forma favorita de testar tipos / classes é a isinstance construída na função.
Determinar o tipo de um objecto Python
Determinar o tipo de objecto com type
>>> obj = object()
>>> type(obj)
<class 'object'>
Apesar de funcionar, evite atributos duplos como __class__
- eles não são semanticamente públicos, e, embora talvez não neste caso, as funções de construção geralmente têm um melhor comportamento.
>>> obj.__class__ # avoid this!
<class 'object'>
Verificação do tipo
Bem, essa é uma pergunta diferente, não use o tipo de uso.Existe uma maneira simples de determinar se uma variável é uma lista, dicionário, ou algo mais? Estou a recuperar um objecto que pode ser qualquer um dos tipos e eu preciso ser capaz de dizer a diferença.
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)
Isto cobre o caso em que o seu utilizador pode estar a fazer algo inteligente ou sensato subclassificando {[[8]} - de acordo com o princípio da substituição de Liskov, você quer ser capaz de usar subclass instâncias sem quebrar o seu código - e isinstance
apoia isto.
Usar As Abstracções
Ainda melhor, podes procurar uma classe de base abstracta específica decollections
ou 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)
Ou não Digitas explicitamente a verificação
Ou, talvez o melhor de tudo, use a datilografia de pato, e não digite explicitamente o seu código. A datilografia de patos suporta a substituição de Liskov com mais elegância e menos verbosidade.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)
Conclusão
- usar
type
para realmente obter a classe de uma instância. - usar
isinstance
para verificar explicitamente as subclasses reais ou as abstracções registadas. - e apenas evite o tipo de verificação onde faz sentido.
Pode utilizar type()
ou isinstance()
.
>>> type([]) is list
True
Esteja avisado que pode bater list
ou qualquer outro tipo atribuindo uma variável no âmbito actual do mesmo nome.
>>> the_d = {}
>>> t = lambda x: "aight" if type(x) is dict else "NOPE"
>>> t(the_d) 'aight'
>>> dict = "dude."
>>> t(the_d) 'NOPE'
Acima vemos que dict
é transferido para uma cadeia, portanto o teste:
type({}) is dict
...falha.
Para contornar isto e utilizar {[4] } mais cuidadosamente:
>>> import __builtin__
>>> the_d = {}
>>> type({}) is dict
True
>>> dict =""
>>> type({}) is dict
False
>>> type({}) is __builtin__.dict
True
Enquanto as perguntas são muito antigas, eu tropecei nisto enquanto descobria uma maneira própria, e acho que ainda precisa de ser esclarecida, pelo menos para o Python 2.x (não verificou o Python 3, mas como a questão surge com classes clássicas que se foram em tal versão, provavelmente não importa).
Aqui estou eu a tentar responder à pergunta do título: Como posso determinar o tipo de um objecto arbitrário ? Outras sugestões sobre usar ou não usar isinstance são muito bem em muitos comentários e respostas, mas não estou a responder a essas preocupações.
O principal problema com a abordagem type()
é que não funciona adequadamente com instâncias de estilo antigo.:
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
Executar este excerto renderia:
Are o and t instances of the same class? True
O que, eu diria, não é o que a maioria das pessoas esperaria.
A abordagem __class__
é a mais próxima da correcção, mas não funcionará num caso crucial: quando o objecto aprovado é um antigo estilo classe (não um exemplo!), uma vez que esses objetos não possuem tal atributo.
#!/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
collections.abc
que contém várias classes abstratas de base (ABCs) que complementam a datilografia de patos.
Por exemplo, em vez de verificar explicitamente se algo é uma lista com:
isinstance(my_obj, list)
Você poderia, se você só está interessado em ver se o objeto que você tem permite obter itens, use collections.abc.Sequence
:
from collections.abc import Sequence
isinstance(my_obj, Sequence)
Se você está estritamente interessado em objetos que permitem obter, definir e apagar itens (i. e. sequências mutáveis), Você optaria por collections.abc.MutableSequence
.
Muitos outros ABCs são definidos lá, Mapping
para objectos que podem ser usados como mapas, Iterable
, Callable
, etc. Uma lista completa de todos estes pode ser vista em a documentação para collections.abc
.
Tenha cuidado com isinstance
isinstance(True, bool)
True
>>> isinstance(True, int)
True
Mas Tipo
type(True) == bool
True
>>> type(True) == int
False