Questo codice non è corretto a meno che non si sa qualcosa che noi non sappiamo:
if isinstance(data, bytes):
data = data.decode()
Non è (sembri) conosce la codifica dei data
. Stai assumendo it's UTF-8, ma potrebbe benissimo essere sbagliato. Dal momento che non si conosce la codifica, you do not have text. Hai byte, che potrebbero avere qualsiasi significato sotto il sole.
La buona notizia è che la maggior parte delle sequenze casuali di byte non è UTF-8 valida, quindi quando si interrompe, si romperà rumorosamente (errors='strict'
è l'impostazione predefinita) invece di fare silenziosamente la cosa sbagliata. La notizia ancora migliore è che la maggior parte di quelle sequenze casuali che sono valide come UTF-8 sono anche ASCII valide, che (nearly) sono tutti d'accordo su come analizzare comunque.
La cattiva notizia è che non esiste un modo ragionevole per risolvere questo problema. Esiste un modo standard per fornire informazioni sulla codifica: utilizzare str
anziché bytes
. Se alcuni codici di terze parti ti hanno consegnato un oggetto bytes
o bytearray
senza ulteriori contesti o informazioni, l'unica azione corretta è fallire.
Ora, supponendo che si conosce la codifica, è possibile utilizzare functools.singledispatch
qui:
@functools.singledispatch
def foo(data, other_arguments, ...):
raise TypeError('Unknown type: '+repr(type(data)))
@foo.register(str)
def _(data, other_arguments, ...):
# data is a str
@foo.register(bytes)
@foo.register(bytearray)
def _(data, other_arguments, ...):
data = data.decode('encoding')
# explicit is better than implicit; don't leave the encoding out for UTF-8
return foo(data, other_arguments, ...)
Questo non funziona sui metodi, e data
deve essere il primo argomento. Se quelle restrizioni non funzionano per te, usa invece una delle altre risposte.
Personalmente, adoro il dattilografo di Python tanto quanto il ragazzo successivo. Ma se hai bisogno di fare controlli sui tuoi argomenti di input e forzare a tipi diversi, allora non stai più digitando - Stai rendendo il tuo codice più difficile da leggere in una manutenzione. Il mio suggerimento qui (e altri potrebbero non essere d'accordo) sarebbe quello di rendere più funzioni (che gestiscono il tipo di coercizione e delegare a un'implementazione di base). – mgilson
(1) A meno che non sia necessario per la compatibilità con il codice legacy Python 2; evitare di accettare contemporaneamente sia testo che dati binari. Se la tua funzione funziona con il testo, allora dovrebbe accettare solo 'str'. Qualche altro codice dovrebbe convertirsi da byte in Unicode in input il prima possibile. (2) "byte-like" ha un significato speciale in Python (oggetti che supportano il protocollo buffer (solo C)) – jfs