Informazioni su digitazione anatra :
Duck typing is aided by habitually not testing for the type of arguments in method and function bodies, relying on documentation, clear code and testing to ensure correct use.
Informazioni sulla convalida degli argomenti (EAFP: è più facile chiedere perdono che il permesso). Un esempio adattato da qui :
...it is considered more pythonic to do :
def my_method(self, key):
try:
value = self.a_dict[member]
except TypeError:
# do something else
This means that anyone else using your code doesn't have to use a real dictionary or subclass - they can use any object that implements the mapping interface.
Unfortunately in practise it's not that simple. What if member in the above example might be an integer ? Integers are immutable - so it's perfectly reasonable to use them as dictionary keys. However they are also used to index sequence type objects. If member happens to be an integer then example two could let through lists and strings as well as dictionaries.
Informazioni sulla assertiva programmazione:
Assertions are a systematic way to check that the internal state of a program is as the programmer expected, with the goal of catching bugs. In particular, they're good for catching false assumptions that were made while writing the code, or abuse of an interface by another programmer. In addition, they can act as in-line documentation to some extent, by making the programmer's assumptions obvious. ("Explicit is better than implicit.")
I concetti menzionati sono a volte in conflitto, quindi conto i seguenti fattori quando scelgo se non eseguo alcuna convalida dei dati, faccio validazioni o asserzioni forti:
-
strong convalida. Per validazione strong intendo aumentare un'eccezione personalizzata (
ApiError
ad esempio). Se la mia funzione / metodo è parte di un'API pubblica, è meglio convalidare l'argomento per mostrare un buon messaggio di errore sul tipo inatteso. Controllando il tipo non intendo solo l'utilizzo diisinstance
, ma anche se l'oggetto passato supporta l'interfaccia necessaria (digitazione anatra). Mentre registro l'API e specifica il tipo previsto e l'utente potrebbe voler utilizzare la mia funzione in modo inaspettato, mi sento più sicuro quando controllo le ipotesi. Di solito usoisinstance
e se successivamente voglio supportare altri tipi o anatre, cambio la logica di validazione. -
Programmazione assertiva. Se il mio codice è nuovo, io uso molto. Quali sono i tuoi consigli in merito? In seguito rimuovi gli asserzioni dal codice?
-
Se la mia funzione / metodo non fa parte di un'API, ma passa alcuni dei suoi argomenti attraverso un altro codice non scritto, studiato o testato da me, faccio un sacco di asserti in base all'interfaccia chiamata. La mia logica dietro questo - meglio fallire nel mio codice, poi da qualche parte 10 livelli più profondi in stacktrace con errore incomprensibile che costringe a fare il debug molto e poi ad aggiungere l'assert al mio codice comunque.
Commenti e consigli su quando utilizzare o non utilizzare la convalida tipo / valore, afferma? Scusa se non la migliore formulazione della domanda.
Ad esempio, considera la seguente funzione, dove Customer
è un modello dichiarativo di 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 convalida:
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 usare ognuno di questi nel contesto della digitazione anatra, controllo del tipo, convalida dei dati?