Qual è il modo migliore per verificare se un determinato oggetto è di un determinato tipo? Che ne dici di verificare se l'oggetto eredita da un determinato tipo?
Diciamo che ho un oggetto o
. Come posso verificare se si tratta di un str
?
Qual è il modo migliore per verificare se un determinato oggetto è di un determinato tipo? Che ne dici di verificare se l'oggetto eredita da un determinato tipo?
Diciamo che ho un oggetto o
. Come posso verificare se si tratta di un str
?
Risposte:
Per verificare se o
è un'istanza str
o una sottoclasse di str
, utilizzare isinstance (questo sarebbe il modo "canonico"):
if isinstance(o, str):
Per verificare se il tipo di o
è esattamente str
(escludi le sottoclassi):
if type(o) is str:
Inoltre, funziona e può essere utile in alcuni casi:
if issubclass(type(o), str):
Vedere Funzioni integrate nel Riferimento della libreria Python per informazioni pertinenti.
Un'altra nota: in questo caso, se stai usando Python 2, potresti effettivamente voler usare:
if isinstance(o, basestring):
perché questo catturerà anche stringhe Unicode ( unicode
non è una sottoclasse di str
; entrambe str
e unicode
sono sottoclassi di basestring
). Nota che basestring
non esiste più in Python 3, dove esiste una stretta separazione di stringhe ( str
) e dati binari ( bytes
).
In alternativa, isinstance
accetta una tupla di classi. Questo restituirà True
se o
è un'istanza di una sottoclasse di uno di (str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
allora non è vero anche quello isinstance(a, Object)
. Tuttavia, se type(a) is SubClassOfObject
, allora type(a) is Object == False
, ma isinstance(a, Object) == True
. Giusto?
a is b
significa che aeb sono esattamente la stessa cosa, cioè riferimenti alla stessa entità in memoria. Quindi a
e b
dovrebbe essere esattamente la stessa classe, non sottoclassi, come con isinstance()
. Vedi ad esempio stackoverflow.com/a/133024/1072212
Il modo più Pythonic per controllare il tipo di un oggetto è ... non controllarlo.
Poiché Python incoraggia Duck Typing , dovresti semplicemente try...except
usare i metodi dell'oggetto nel modo in cui vuoi usarli. Quindi, se la tua funzione è alla ricerca di un oggetto file scrivibile, non controllare che sia una sottoclasse di file
, prova solo a usare il suo .write()
metodo!
Certo, a volte queste belle astrazioni si rompono ed isinstance(obj, cls)
è quello che ti serve. Ma usa con parsimonia.
if hasattr(ob, "write") and callable(ob.write):
O salvare un po 'di accesso al dict ...func = getattr(ob, "write", None)
if callable(func): ...
hasattr
solo un AttributeError - Vedi: docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
restituirà True
if o
è un str
o è di un tipo che eredita da str
.
type(o) is str
restituirà True
se e solo se o
è uno str. Restituirà False
se o
è di un tipo che eredita da str
.
isinstance
e type(var) == type('')
non è chiara.
Dopo che la domanda è stata posta e risposta, i suggerimenti sul tipo sono stati aggiunti a Python . I suggerimenti sul tipo in Python consentono di controllare i tipi, ma in modo molto diverso dai linguaggi tipizzati staticamente. I suggerimenti sul tipo in Python associano i tipi previsti di argomenti alle funzioni come dati accessibili in runtime associati alle funzioni e ciò consente di verificare i tipi. Esempio di sintassi del suggerimento tipo:
def foo(i: int):
return i
foo(5)
foo('oops')
In questo caso vogliamo che venga attivato un errore foo('oops')
poiché è il tipo annotato dell'argomento int
. Il suggerimento sul tipo aggiunto non provoca un errore quando lo script viene eseguito normalmente. Tuttavia, aggiunge attributi alla funzione che descrive i tipi previsti che altri programmi possono interrogare e utilizzare per verificare la presenza di errori di tipo.
Uno di questi altri programmi che è possibile utilizzare per trovare l'errore di tipo è mypy
:
mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(Potrebbe essere necessario installarlo mypy
dal gestore dei pacchetti. Non credo che venga fornito con CPython ma sembra avere un certo livello di "ufficialità".)
Il controllo del tipo in questo modo è diverso dal controllo del tipo nei linguaggi compilati digitati staticamente. Poiché i tipi sono dinamici in Python, la verifica dei tipi deve essere eseguita in fase di esecuzione, il che comporta un costo, anche su programmi corretti, se insistiamo sul fatto che ciò avvenga in ogni occasione. I controlli espliciti sui tipi possono anche essere più restrittivi del necessario e causare errori non necessari (ad esempio, l'argomento deve davvero essere del list
tipo esatto o è qualcosa di assolutamente iterabile?).
L'aspetto positivo del controllo esplicito del tipo è che può rilevare errori in precedenza e fornire messaggi di errore più chiari rispetto alla digitazione duck. I requisiti esatti di un tipo di anatra possono essere espressi solo con documentazione esterna (si spera che sia accurata e accurata) e errori di tipi incompatibili possono verificarsi lontano da dove hanno origine.
I suggerimenti sui tipi di Python hanno lo scopo di offrire un compromesso in cui i tipi possono essere specificati e controllati ma non ci sono costi aggiuntivi durante la normale esecuzione del codice.
Il typing
pacchetto offre variabili di tipo che possono essere utilizzate nei suggerimenti di tipo per esprimere i comportamenti necessari senza richiedere tipi particolari. Ad esempio, include variabili come Iterable
e Callable
per i suggerimenti per specificare la necessità di qualsiasi tipo con tali comportamenti.
Mentre i suggerimenti sul tipo sono il modo più Pythonic per controllare i tipi, spesso è ancora più Pythonic a non controllare affatto i tipi e fare affidamento sulla tipizzazione duck. I suggerimenti sul tipo sono relativamente nuovi e la giuria è ancora fuori quando sono la soluzione più Pythonic. Un confronto relativamente non controverso ma molto generale: i suggerimenti sul tipo forniscono una forma di documentazione che può essere applicata, consente al codice di generare errori precedenti e di più facile comprensione, può rilevare errori che la tipizzazione anatra non può e può essere controllata staticamente (in modo insolito senso ma è ancora al di fuori del runtime). D'altra parte, la tipizzazione anatra è stata per molto tempo il modo Pythonic, non impone il sovraccarico cognitivo della tipizzazione statica, è meno dettagliata e accetterà tutti i tipi vitali e poi alcuni.
mypy
è un modulo Python che utilizza importlib
per accedere a tali dati. Se si tratti di "controllo statico del tipo" è una domanda filosofica, ma è diversa da ciò che la maggior parte si aspetterebbe dal momento che sono coinvolti il normale interprete di linguaggio e le macchine di importazione.
Ecco un esempio per cui la digitazione delle anatre è cattiva senza sapere quando è pericolosa. Ad esempio: ecco il codice Python (forse omettendo il rientro corretto), nota che questa situazione è evitabile prendendoti cura delle funzioni isinstance e issubclassof per assicurarti che quando hai davvero bisogno di un'anatra, non ottieni una 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)
discorso e sovrascriverlo (). O più probabilmente, class ChineseCancerDuck(Duck)
con un brutto effetto collaterale che non si manifesta fino a anni dopo. Faresti meglio a sorvegliare tuo figlio (e testare a fondo i suoi giocattoli :)
__file__
attributo (comunemente usato per identificare oggetti simili a file) per significare qualcos'altro.
isinstance(o, str)
Penso che la cosa bella dell'uso di un linguaggio dinamico come Python sia che non dovresti davvero controllare qualcosa del genere.
Vorrei solo chiamare i metodi richiesti sul tuo oggetto e catturare un AttributeError
. In seguito ciò ti consentirà di chiamare i tuoi metodi con altri oggetti (apparentemente non correlati) per eseguire diverse attività, come deridere un oggetto per il test.
L'ho usato molto per ottenere dati dal Web con i urllib2.urlopen()
quali restituisce un file come un oggetto. A sua volta, questo può essere passato a quasi tutti i metodi che leggono da un file, perché implementa lo stesso read()
metodo di un file reale.
Ma sono sicuro che ci sia un tempo e un luogo per l'uso isinstance()
, altrimenti probabilmente non ci sarebbe :)
Per convalide di tipi più complessi mi piace l'approccio di typeguard alla validazione basato su annotazioni di suggerimenti di 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)
Puoi eseguire validazioni molto complesse in modo molto pulito e leggibile.
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
Puoi controllare il tipo di una variabile usando __name__ di un 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'
A Hugo:
Probabilmente intendi list
piuttosto che array
, ma questo indica l'intero problema con il controllo del tipo: non vuoi sapere se l'oggetto in questione è un elenco, vuoi sapere se è un qualche tipo di sequenza o se è un singolo oggetto. Quindi prova a usarlo come una sequenza.
Supponi di voler aggiungere l'oggetto a una sequenza esistente oppure, se si tratta di una sequenza di oggetti, aggiungili tutti
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
Un trucco con questo è se stai lavorando con stringhe e / o sequenze di stringhe - è difficile, dato che una stringa viene spesso considerata come un singolo oggetto, ma è anche una sequenza di caratteri. Peggio ancora, in quanto è davvero una sequenza di stringhe a lunghezza singola.
Di solito scelgo di progettare la mia API in modo che accetti solo un singolo valore o una sequenza - semplifica le cose. Non è difficile mettere un [ ]
valore intorno al tuo singolo valore quando lo passi, se necessario.
(Anche se questo può causare errori con le stringhe, come sembrano (sono) sequenze.)
Un modo semplice per controllare il tipo è di confrontarlo con qualcosa di cui conosci il tipo.
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
Penso che il modo migliore sia digitare bene le tue variabili. Puoi farlo usando la libreria "digitando".
Esempio:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
) `
Puoi controllare con la riga sotto per verificare quale tipo di carattere è il valore dato:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)