Domanda

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 ?

È stato utile?

Soluzione

Per verificare se o è un'istanza di 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 (esclude le sottoclassi):

if type(o) is str:

Anche il seguente funziona e può essere utile in alcuni casi:

if issubclass(type(o), str):

Vedi Funzioni integrate nella Python Library Reference 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 ; sia str che unicode sono sottoclassi di basestring ). Nota che basestring non esiste più in Python 3, dove c'è una rigorosa separazione di stringhe ( str ) e dati binari ( byte ).

In alternativa, isinstance accetta una tupla di classi. Ciò restituirà True se x è un'istanza di una sottoclasse di qualsiasi (str, unicode):

if isinstance(o, (str, unicode)):

Altri suggerimenti

Il più metodo Pythonic per controllare il tipo di un oggetto è ... non per controllarlo.

Poiché Python incoraggia Duck Typing , dovresti semplicemente provare ... tranne utilizzare i metodi dell'oggetto nel modo in cui si desidera utilizzarli. Quindi, se la tua funzione è alla ricerca di un oggetto file scrivibile, non controlla che sia una sottoclasse di file , prova a usare il suo .write () method!

Certo, a volte queste belle astrazioni si rompono e isinstance (obj, cls) è ciò di cui hai bisogno. Ma usa con parsimonia.

isinstance (o, str) restituirà True se 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 .

Dopo la domanda e la risposta alla domanda, sono stati aggiunti suggerimenti di tipo a Python . I suggerimenti sul tipo in Python consentono di controllare i tipi, ma in un modo molto diverso dai linguaggi digitati staticamente. I suggerimenti sui tipi in Python associano i tipi previsti di argomenti alle funzioni come dati accessibili in runtime associati alle funzioni e questo consente per i tipi da controllare. 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 per foo ('oops') poiché il tipo annotato dell'argomento è int . Il suggerimento sul tipo aggiunto non causa 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 installare mypy dal gestore dei pacchetti. Non credo che sia fornito con CPython ma sembra avere un certo livello di "quotazione ufficiale").

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 tipo esattamente list o è abbastanza 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 anatra. I requisiti esatti di un tipo di anatra possono essere espressi solo con documentazione esterna (si spera sia accurata e accurata) e errori di tipi incompatibili possono verificarsi lontano da dove hanno origine.

I suggerimenti sul tipo 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 pacchetto typing 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 sui tipi 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 digitazione anatra non può e può essere verificata 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.

Ecco un esempio del perché la tipizzazione delle anatre è malvagia senza sapere quando è pericolosa. Ad esempio: ecco il codice Python (eventualmente omettendo il rientro corretto), si noti che questo la situazione è evitabile prendendosi cura delle funzioni di isinstance e issubclassof per assicurarsi che quando si ha davvero bisogno di un'anatra, non si ottiene 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()
isinstance(o, str)

Link ai documenti

Penso che il bello dell'utilizzo 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 quando ho rimosso i dati dal web con urllib2.urlopen () che restituisce un oggetto come . Questo può a sua volta passare a quasi tutti i metodi che leggono da un file, perché implementa lo stesso metodo read () di un file reale.

Ma sono sicuro che c'è un tempo e un luogo per usare isinstance () , altrimenti probabilmente non ci sarebbe :)

A Hugo:

Probabilmente intendi list anziché array , ma questo indica l'intero problema con il controllo del tipo: non vuoi sapere se l'oggetto in questione è un lista, 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, poiché 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 [] attorno al tuo singolo valore quando lo passi, se necessario.

(Anche se questo può causare errori con le stringhe, come sembrano (sono) sequenze.)

Per convalide di tipi più complessi mi piace l'approccio di typeguard di convalida 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 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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top