Informazioni sulla digitazione dell'anatra :
La tipizzazione delle anatre è aiutata dal non testare abitualmente il tipo di argomenti negli organismi metodo e funzione, basandosi sulla documentazione, sul codice chiaro e sui test per garantire un uso corretto.
Informazioni sulla convalida dell'argomento (EAFP: è più facile chiedere perdono che autorizzazione). Un esempio adattato da qui :
... è considerato più pitonico da fare:
def my_method(self, key):
try:
value = self.a_dict[member]
except TypeError:
# do something else
Ciò significa che chiunque utilizzi il tuo codice non deve utilizzare un dizionario o una sottoclasse reale: può utilizzare qualsiasi oggetto che implementa l'interfaccia di mappatura.
Purtroppo in pratica non è così semplice. Cosa succede se il membro nell'esempio precedente potrebbe essere un numero intero? I numeri interi sono immutabili, quindi è perfettamente ragionevole usarli come chiavi del dizionario. Tuttavia, vengono anche utilizzati per indicizzare oggetti di tipo sequenza. Se un membro risulta essere un numero intero, l'esempio due potrebbe passare attraverso elenchi e stringhe nonché dizionari.
Informazioni sulla programmazione assertiva :
Le asserzioni sono un modo sistematico per verificare che lo stato interno di un programma sia come previsto dal programmatore, con l'obiettivo di catturare i bug. In particolare, sono utili per rilevare false assunzioni fatte durante la scrittura del codice o per abuso di un'interfaccia da parte di un altro programmatore. Inoltre, possono fungere da documentazione in linea in una certa misura, rendendo evidenti le ipotesi del programmatore. ("Esplicito è meglio che implicito.")
I concetti citati a volte sono in conflitto, quindi conto sulla scelta se non eseguo alcuna convalida dei dati, eseguo una convalida forte o utilizzo assert:
Convalida forte. Con convalida forte intendo sollevare un'eccezione personalizzata (
ApiError
ad esempio). Se la mia funzione / metodo fa parte di un'API pubblica, è meglio convalidare l'argomento per mostrare un buon messaggio di errore sul tipo imprevisto. Controllando il tipo non intendo solo usareisinstance
, ma anche se l'oggetto passato supporta l'interfaccia necessaria (digitando duck). Mentre documento l'API e specifico il tipo previsto e l'utente potrebbe voler utilizzare la mia funzione in modo imprevisto, mi sento più sicuro quando controllo le ipotesi. Di solito usoisinstance
e se in seguito voglio supportare altri tipi o anatre, cambio la logica di validazione.Programmazione assertiva. Se il mio codice è nuovo, utilizzo molto le asserzioni. Quali sono i tuoi consigli su questo? Rimuovere successivamente le asserzioni dal codice?
Se la mia funzione / metodo non fa parte di un'API, ma passa alcuni dei suoi argomenti a un altro codice non scritto, studiato o testato da me, faccio molte affermazioni secondo l'interfaccia chiamata. La mia logica dietro questo - meglio fallire nel mio codice, quindi da qualche parte 10 livelli più profondi in stacktrace con errore incomprensibile che costringe a eseguire il debug molto e successivamente aggiungere l'asserzione al mio codice.
Commenti e consigli su quando utilizzare o meno la convalida del tipo / valore, afferma? Ci scusiamo per non avere la migliore formulazione della domanda.
Ad esempio, prendere in considerazione la seguente funzione, dove si Customer
trova un modello dichiarativo SQLAlchemy:
def add_customer(self, customer):
"""Save new customer into the database.
@param customer: Customer instance, whose id is None
@return: merged into global session customer
"""
# no validation here at all
# let's hope SQLAlchemy session will break if `customer` is not a model instance
customer = self.session.add(customer)
self.session.commit()
return customer
Quindi, ci sono diversi modi per gestire la validazione:
def add_customer(self, customer):
# this is an API method, so let's validate the input
if not isinstance(customer, Customer):
raise ApiError('Invalid type')
if customer.id is not None:
raise ApiError('id should be None')
customer = self.session.add(customer)
self.session.commit()
return customer
o
def add_customer(self, customer):
# this is an internal method, but i want to be sure
# that it's a customer model instance
assert isinstance(customer, Customer), 'Achtung!'
assert customer.id is None
customer = self.session.add(customer)
self.session.commit()
return customer
Quando e perché dovresti utilizzare ognuno di questi nel contesto della tipizzazione anatra, del controllo del tipo, della convalida dei dati?