Qual é a melhor maneira de verificar se um determinado objeto é de um determinado tipo? Que tal verificar se o objeto herda de um determinado tipo?
Digamos que eu tenho um objeto o
. Como verifico se é um str
?
Qual é a melhor maneira de verificar se um determinado objeto é de um determinado tipo? Que tal verificar se o objeto herda de um determinado tipo?
Digamos que eu tenho um objeto o
. Como verifico se é um str
?
Respostas:
Para verificar se o
é uma instância str
ou qualquer subclasse de str
, use isinstance (essa seria a maneira "canônica"):
if isinstance(o, str):
Para verificar se o tipo de o
é exatamente str
(excluir subclasses):
if type(o) is str:
O seguinte também funciona e pode ser útil em alguns casos:
if issubclass(type(o), str):
Consulte Funções internas na Referência da biblioteca Python para obter informações relevantes.
Mais uma observação: nesse caso, se você estiver usando o Python 2, poderá usar:
if isinstance(o, basestring):
porque isso também captura seqüências de caracteres Unicode ( unicode
não é uma subclasse de str
; both str
e unicode
são subclasses de basestring
). Observe que basestring
não existe mais no Python 3, onde há uma separação estrita de strings ( str
) e dados binários ( bytes
).
Como alternativa, isinstance
aceita uma tupla de classes. Isso retornará True
se o
for uma instância de qualquer subclasse de qualquer um de (str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
então não é verdade também isinstance(a, Object)
. No entanto, se type(a) is SubClassOfObject
, então type(a) is Object == False
, mas isinstance(a, Object) == True
. Direita?
a is b
significa que aeb são exatamente a mesma coisa, ou seja, referências à mesma entidade na memória. Então, a
e b
teria que ser exatamente a mesma classe, não subclasses, como acontece com isinstance()
. Veja por exemplo stackoverflow.com/a/133024/1072212
A maneira mais pitônica de verificar o tipo de um objeto é ... não verificá-lo.
Como o Python incentiva o Duck Typing , você deve try...except
usar os métodos do objeto da maneira que deseja. Portanto, se sua função estiver procurando por um objeto de arquivo gravável, não verifique se é uma subclasse de file
, apenas tente usar seu .write()
método!
É claro que, algumas vezes, essas abstrações agradáveis quebram e isinstance(obj, cls)
é o que você precisa. Mas use com moderação.
if hasattr(ob, "write") and callable(ob.write):
Ou poupar algum acesso dict ...func = getattr(ob, "write", None)
if callable(func): ...
hasattr
apenas suprime um AttributeError - Veja: docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
retornará True
se o
é um str
ou é de um tipo que herda str
.
type(o) is str
retornará True
se e somente se o
for um str. Ele retornará False
se o
for de um tipo que herda str
.
isinstance
e type(var) == type('')
não é clara.
Depois que a pergunta foi feita e respondida, dicas de tipo foram adicionadas ao Python . Dicas de tipo no Python permitem que os tipos sejam verificados, mas de uma maneira muito diferente das linguagens estaticamente tipadas. Dicas de tipo no Python associam os tipos esperados de argumentos a funções como dados acessíveis em tempo de execução associados a funções e isso permite que tipos sejam verificados. Exemplo de sintaxe do tipo dica:
def foo(i: int):
return i
foo(5)
foo('oops')
Nesse caso, queremos que um erro seja acionado por foo('oops')
já que o tipo anotada do argumento é int
. A dica de tipo adicionado não causa um erro quando o script é executado normalmente. No entanto, ele adiciona atributos à função que descreve os tipos esperados que outros programas podem consultar e usar para verificar se há erros de tipo.
Um desses outros programas que podem ser usados para encontrar o erro de tipo é mypy
:
mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(Talvez você precise instalar a mypy
partir do seu gerenciador de pacotes. Não acho que ele seja fornecido com o CPython, mas parece ter algum nível de "oficialidade".)
A verificação de tipo dessa maneira é diferente da verificação de tipo em idiomas compilados estaticamente. Como os tipos são dinâmicos no Python, a verificação de tipo deve ser feita em tempo de execução, o que impõe um custo - mesmo em programas corretos - se insistirmos que isso ocorra a todo momento. Verificações explícitas de tipo também podem ser mais restritivas do que o necessário e causar erros desnecessários (por exemplo, o argumento realmente precisa ser exatamentelist
tipo ou alguma coisa iterável é suficiente?).
A vantagem da verificação explícita de tipo é que ela pode capturar erros mais cedo e fornecer mensagens de erro mais claras do que a digitação de pato. Os requisitos exatos de um tipo de pato só podem ser expressos com documentação externa (espero que seja completa e precisa) e erros de tipos incompatíveis possam ocorrer longe de onde eles se originam.
As dicas de tipo do Python são destinadas a oferecer um compromisso onde os tipos podem ser especificados e verificados, mas não há custo adicional durante a execução normal do código.
O typing
pacote oferece variáveis de tipo que podem ser usadas em dicas de tipo para expressar comportamentos necessários sem exigir tipos específicos. Por exemplo, inclui variáveis como Iterable
e Callable
para dicas para especificar a necessidade de qualquer tipo com esses comportamentos.
Embora as dicas de tipo sejam a maneira mais pitônica de verificar os tipos, muitas vezes é ainda mais pitônico não verificar os tipos e confiar na digitação do pato. As dicas de tipo são relativamente novas e o júri ainda não se manifestou quando é a solução mais pitônica. Uma comparação relativamente incontroversa, mas muito geral: as dicas de tipo fornecem uma forma de documentação que pode ser aplicada, permitem que o código gere erros mais cedo e mais fáceis de entender, podem detectar erros que a digitação de pato não pode e podem ser verificados estaticamente (de maneira incomum mas ainda está fora do tempo de execução). Por outro lado, a tipagem de patos é o caminho pitônico há muito tempo, não impõe a sobrecarga cognitiva da tipagem estática, é menos detalhada e aceita todos os tipos viáveis e mais alguns.
mypy
é um módulo Python usado importlib
para acessar esses dados. Se isso é "verificação de tipo estático" é uma questão filosófica, mas é diferente do que a maioria esperaria, pois o intérprete de linguagem normal e o mecanismo de importação estão envolvidos.
Aqui está um exemplo de como digitar patos é ruim sem saber quando é perigoso. Por exemplo: Aqui está o código Python (possivelmente omitindo o recuo adequado), observe que essa situação é evitável cuidando da instância e da subclasse de funções para garantir que, quando você realmente precisa de um pato, não receba uma bomba.
class Bomb:
def __init__(self):
""
def talk(self):
self.explode()
def explode(self):
print "BOOM!, The bomb explodes."
class Duck:
def __init__(self):
""
def talk(self):
print "I am a duck, I will not blow up if you ask me to talk."
class Kid:
kids_duck = None
def __init__(self):
print "Kid comes around a corner and asks you for money so he could buy a duck."
def takeDuck(self, duck):
self.kids_duck = duck
print "The kid accepts the duck, and happily skips along"
def doYourThing(self):
print "The kid tries to get the duck to talk"
self.kids_duck.talk()
myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
class EvilDuck(Duck)
e substituir talk (). Ou, mais provavelmente, class ChineseCancerDuck(Duck)
com um efeito colateral desagradável que só aparece anos depois. Você seria melhor fora apenas supervisionar o seu filho (e testar exaustivamente seus brinquedos :)
__file__
atributo (geralmente usado para identificar objetos semelhantes a arquivos) para significar outra coisa.
isinstance(o, str)
Eu acho que o legal de usar uma linguagem dinâmica como Python é que você realmente não deveria ter que verificar algo assim.
Eu chamaria os métodos necessários em seu objeto e pegaria um AttributeError
. Posteriormente, isso permitirá que você chame seus métodos com outros objetos (aparentemente não relacionados) para realizar tarefas diferentes, como zombar de um objeto para teste.
Eu usei muito isso ao obter dados da Web com os urllib2.urlopen()
quais retorna um arquivo como objeto. Por sua vez, isso pode ser passado para quase qualquer método que leia de um arquivo, porque implementa o mesmo read()
método que um arquivo real.
Mas tenho certeza de que há um tempo e um local para usar isinstance()
, caso contrário, provavelmente não estaria lá :)
Para validações de tipo mais complexas, eu gosto da abordagem de validação do typeguard com base nas anotações de dicas do tipo python:
from typeguard import check_type
from typing import List
try:
check_type('mylist', [1, 2], List[int])
except TypeError as e:
print(e)
Você pode executar validações muito complexas de maneira muito limpa e legível.
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
Você pode verificar o tipo de uma variável usando __name__ de um tipo.
Ex:
>>> a = [1,2,3,4]
>>> b = 1
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'
Para Hugo:
Você provavelmente quer dizer, em list
vez dearray
, mas isso aponta para todo o problema com a verificação de tipo - você não quer saber se o objeto em questão é uma lista, deseja saber se é algum tipo de sequência ou se é um único objeto. Portanto, tente usá-lo como uma sequência.
Digamos que você queira adicionar o objeto a uma sequência existente ou, se for uma sequência de objetos, adicione todos eles
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
Um truque é se você estiver trabalhando com strings e / ou sequências de strings - isso é complicado, já que uma string é frequentemente vista como um único objeto, mas também é uma sequência de caracteres. Pior que isso, já que é realmente uma sequência de strings de comprimento único.
Normalmente, escolho projetar minha API para que ela aceite apenas um único valor ou uma sequência - isso facilita as coisas. Não é difícil colocar um[ ]
valor único quando você o transmite, se necessário.
(Embora isso possa causar erros nas seqüências de caracteres, como elas parecem seqüências).
Uma maneira simples de verificar o tipo é compará-lo com algo cujo tipo você conhece.
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
Eu acho que a melhor maneira é digitar bem suas variáveis. Você pode fazer isso usando a biblioteca "digitando".
Exemplo:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
) `
Você pode verificar com a linha abaixo para verificar qual tipo de caractere é o valor fornecido:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)