vocali - stringa inizia con python




Come posso controllare le variabili in Python? (6)

Ho una funzione Python che accetta un argomento numerico che deve essere un numero intero in modo che si comporti correttamente. Qual è il modo preferito per verificarlo in Python?

La mia prima reazione è di fare qualcosa del genere:

def isInteger(n):
    return int(n) == n

Ma non posso fare a meno di pensare che questo è 1) costoso 2) brutto e 3) soggetto alla tenera compassione della macchina epsilon.

Python fornisce mezzi nativi per il controllo del tipo di variabili? O questa è considerata una violazione del design dinamico del linguaggio della lingua?

EDIT: dal momento che un numero di persone ha chiesto - l'applicazione in questione funziona con i prefissi IPv4, reperendo i dati da file di testo flat. Se qualsiasi input viene analizzato in un float, tale record deve essere visualizzato come non valido e ignorato.


Sarei tentato di qualcosa di simile:

def check_and_convert(x):
    x = int(x)
    assert 0 <= x <= 255, "must be between 0 and 255 (inclusive)"
    return x

class IPv4(object):
    """IPv4 CIDR prefixes is A.B.C.D/E where A-D are 
       integers in the range 0-255, and E is an int 
       in the range 0-32."""

    def __init__(self, a, b, c, d, e=0):
        self.a = check_and_convert(a)
        self.b = check_and_convert(a)
        self.c = check_and_convert(a)
        self.d = check_and_convert(a)
        assert 0 <= x <= 32, "must be between 0 and 32 (inclusive)"
        self.e = int(e)

In questo modo, quando lo si utilizza, qualsiasi cosa può essere passata, ma si memorizza solo un numero intero valido.


che ne dite di:

def ip(string):
    subs = string.split('.')
    if len(subs) != 4:
        raise ValueError("incorrect input")
    out = tuple(int(v) for v in subs if 0 <= int(v) <= 255)
    if len(out) != 4:
        raise ValueError("incorrect input")
    return out

naturalmente c'è la funzione standard di istanza (3, int) ...


Sì, come ha detto Evan, non digitare check. Prova a usare il valore:

def myintfunction(value):
   """ Please pass an integer """
   return 2 + value

Quello non ha un typecheck. È molto meglio! Vediamo cosa succede quando lo provo:

>>> myintfunction(5)
7

Funziona, perché è un numero intero. Hm. Proviamo un po 'di testo

>>> myintfunction('text')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in myintfunction
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Mostra un errore, TypeError, che è quello che dovrebbe fare comunque. Se il chiamante vuole prenderlo, è possibile.

Cosa faresti se facessi un tipografia? Mostra un errore vero? Quindi non è necessario digitare il tipografico perché l'errore è già visualizzato automaticamente.

Inoltre, poiché non hai digitato il testo, hai la funzione che funzioni con altri tipi:

Galleggia:

>>> print myintfunction(2.2)
4.2

Numeri complessi:

>>> print myintfunction(5j)
(2+5j)

Decimali:

>>> import decimal
>>> myintfunction(decimal.Decimal('15'))
Decimal("17")

Anche oggetti completamente arbitrari che possono aggiungere numeri!

>>> class MyAdderClass(object):
...     def __radd__(self, value):
...             print 'got some value: ', value
...             return 25
... 
>>> m = MyAdderClass()
>>> print myintfunction(m)
got some value:  2
25

Quindi chiaramente non ottieni niente con typechecking. E perdi molto.

AGGIORNARE:

Dal momento che hai modificato la domanda, ora è chiaro che la tua applicazione chiama alcune routine upstream che ha senso solo con gli inte.

Stando così le cose, continuo a pensare che dovresti passare il parametro come ricevuto alla funzione upstream. La funzione upstream la gestirà correttamente, ad es. Generando un errore se necessario. Dubito fortemente che la tua funzione che si occupa degli IP si comporterà stranamente se la passerai a fluttuante. Se puoi darci il nome della biblioteca, possiamo controllarlo per te.

Ma ... Se la funzione upstream si comporterà in modo errato e ucciderà alcuni bambini se passerai un float (ne dubito ancora fortemente), allora semplicemente chiama int() su di esso:

def myintfunction(value):
   """ Please pass an integer """
   return upstreamfunction(int(value))

Non stai ancora eseguendo il controllo ortografico, quindi ottieni i maggiori vantaggi di non eseguire il controllo ortografico.

Se anche dopo tutto questo, si vuole veramente digitare il controllo, nonostante riduca la leggibilità e le prestazioni dell'applicazione senza alcun beneficio, usa un assert per farlo.

assert isinstance(...)
assert type() is xxxx

In questo modo possiamo disattivare assert e rimuovere questa <sarcasm> feature </sarcasm> dal programma chiamandolo come

python -OO program.py

Python ora supporta la digitazione graduale tramite il modulo di digitazione e mypy . Il modulo typing fa parte dello stdlib a partire da Python 3.5 e può essere scaricato da PyPi se hai bisogno di backports per Python 2 o versione precedente di Python 3. Puoi installare mypy eseguendo pip install mypy dalla riga di comando.

In breve, se vuoi verificare che alcune funzioni comprendano un int, un float e restituiscano una stringa, annoterai la tua funzione in questo modo:

def foo(param1: int, param2: float) -> str:
    return "testing {0} {1}".format(param1, param2)

Se il tuo file è stato nominato test.py , puoi digitare typepeck dopo aver installato mypy eseguendo mypy test.py dalla riga di comando.

Se stai usando una versione precedente di Python senza supporto per le annotazioni di funzione, puoi usare i commenti di tipo per ottenere lo stesso effetto:

def foo(param1, param2):
    # type: (int, float) -> str
    return "testing {0} {1}".format(param1, param2)

Si utilizza lo stesso comando mypy test.py per i file Python 3 e mypy --py2 test.py per i file Python 2.

Le annotazioni di tipo vengono ignorate interamente dall'interprete Python in fase di runtime, quindi impongono un minimo o nessun sovraccarico: il solito flusso di lavoro è lavorare sul codice ed eseguire mypy periodicamente per rilevare errori ed errori. Alcuni IDE, come PyCharm, comprenderanno suggerimenti di tipo e possono avvisarti di problemi e digitare disallineamenti nel tuo codice mentre stai modificando direttamente.

Se, per qualche ragione, hai bisogno dei tipi da controllare a runtime (forse devi convalidare molti input?), Dovresti seguire i consigli elencati nelle altre risposte - ad esempio uso isinstance , issubclass e simili. Ci sono anche alcune librerie come enforce che tentano di eseguire typechecking (rispettando le tue annotazioni di tipo) in fase di esecuzione, anche se non sono sicuro di come siano pronti per la produzione al momento della scrittura.

Per ulteriori informazioni e dettagli, consultare il sito Web di mypy , le domande frequenti su mypy e PEP 484 .


La programmazione in Python e l'esecuzione di typechecking come si potrebbe in altre lingue sembrano scegliere un cacciavite con cui sbattere un chiodo. È più elegante usare le funzionalità di gestione delle eccezioni di Python.

Da una riga di comando interattiva, puoi eseguire una dichiarazione come:

int('sometext')

Questo genererà un errore - ipython mi dice:

<type 'exceptions.ValueError'>: invalid literal for int() with base 10: 'sometext'

Ora puoi scrivere del codice come:

try:
   int(myvar) + 50
except ValueError:
   print "Not a number"

Questo può essere personalizzato per eseguire qualsiasi operazione richiesta e per rilevare eventuali errori previsti. Sembra un po 'complicato ma si adatta alla sintassi e agli idiomi di Python e risulta in un codice molto leggibile (una volta che si è abituati a parlare di Python).


isinstance(n, int)

Se hai bisogno di sapere se è sicuramente un int reale e non una sottoclasse di int (generalmente non dovresti averne bisogno):

type(n) is int

Questo:

return int(n) == n

non è una buona idea, dato che i confronti di tipo incrociato possono essere veri - in particolare int(3.0)==3.0





dynamic-typing