2009-03-18 18 views
7

domanda inizialePython: va bene restituire sia booleano che stringa?

Ho fatto una funzione che è in attesa di una particolare stringa di apparire su una porta seriale, e restituisce tutti i caratteri leggere fino a quando è stata trovata la stringa, o falso in caso contrario. Questo è abbastanza conveniente, ma mi stavo chiedendo se è considerato una cattiva pratica o no?

Chiarimento:

L'obiettivo primario è quello di aspettare per una particolare stringa diad apparire in un determinato periodo di tempo. Tranne che per errore IO, il risultato possibile è True (la stringa è apparsa) o False L'obiettivo secondario è ottenere l'intero risultato, perché potrebbero esserci informazioni che vorrei analizzare prima della risposta effettiva che si sta cercando. Ho pensato che potrei combinare l'obiettivo primario e secondario in un valore di ritorno.

def MyFunc(s, timeout) : 
    test = get_some_input(timeout) 
    if test.endswith(s) 
     return test 
    else 
     return False 

Modifica: Un'altra risposta proposta è di sollevare un'eccezione. Non penso che sia una buona idea, perché il timeout è un comportamento previsto. Voglio dire, se c'è un parametro per specificare un timeout, allora un timeout è un possibile risultato, e non un'eccezione.

Modifica 2: Poiché ho bisogno di memorizzare l'input, forse l'utilizzo di una classe è la soluzione giusta. La funzione wait ha un chiaro valore di ritorno, tuttavia è accessibile anche l'intera stringa letta fino al timeout.

class Parser : 
     def __init__(self, sport_name): 
       self.currentMsg = '' 
       self.ser = serial.Serial(sport_name, 115200) 
     def WaitFor(self, s, timeOut=None): 
       self.ser.timeout = timeOut 
       self.currentMsg = '' 
       while self.currentMsg.endswith(s) != True : 
         # should add a try catch here 
         c=self.ser.read() 
         if c != '' : 
           self.currentMsg += c 
         else : 
           print 'timeout waiting for ' + s 
           return False 
       return True 

risposta

6

Sarebbe meglio restituire una stringa AND un booleano (come nel titolo) invece di restituire una stringa O un booleano. Non dovresti dover capire cosa significa il valore di ritorno. Dovrebbe essere totalmente esplicito e le questioni ortogonali dovrebbero essere separate in variabili diverse.

(okay,value) = get_some_input(blah); 
if (okay): print value 

Tendo a non restituire molto le tuple, perché è divertente. Ma è perfettamente valido farlo.

La restituzione di "Nessuno" è una soluzione valida, già menzionata qui.

+0

Quella cosa ortogonale è perfettamente giusta. Quindi restituire una tupla sarebbe una buona soluzione, tuttavia non mi sento ancora molto a mio agio in questo, inoltre l'uso di una classe mi consente di incorporare una porta seriale e consente un'ulteriore estensione. – shodanex

+0

quindi, quale dovrebbe essere il valore se ok è False? – SilentGhost

+0

@SilentGhost: il valore è sempre un input letto fino a quel momento (fino a quando non è stata trovata una stringa o si è verificato un timeout). – jfs

25

Non sarebbe più adatto per restituire un None invece di False?

+0

sì, Nessuno sarebbe più adatto –

+0

ma come descritto in altre risposte, un'eccezione è ancora più Pythonic. –

+0

In questo caso, un'eccezione non è Pythonic. Osserva il comportamento della libreria standard, in particolare select.select e re.match. –

5

In questo caso, è conveniente restituire una stringa vuota.

Inoltre una stringa vuota in Python valuterà comunque su False. Così si può chiamare come:

if Myfunc(s, timeout): 
    print "success" 

Aggiunta: Come sottolineato da S. Lott il vero modo Pythonic è quello di restituire None. Anche se ho scelto di restituire le stringhe nelle funzioni relative alle stringhe. Una questione di preferenza davvero.

Inoltre, suppongo che il chiamante di Myfunc si preoccupi solo di ottenere una stringa su cui manipolare - vuoto o meno. Se il chiamante deve controllare problemi di timeout, ecc. È meglio usare le eccezioni o restituire None.

+0

Il problema con questo design è che non fa distinzione tra timeout in un caso e se test è uguale a "". –

+0

-1: non proprio molto pitonico. Le stringhe vuote sono ancora stringhe. Nessuno è migliore. Un'eccezione è ancora meglio. –

+0

Entrambi i gents di punti validi, hanno modificato la risposta. –

3

Forse se si restituisce una tupla come (False, None) e (True, test), sarebbe meglio, in quanto è possibile valutarli separatamente e non aggiungere complessità non necessaria.

EDIT: Forse la stringa che appare sulla porta seriale è "" (forse previsto), quindi restituire True può dire che è arrivato in quel modo.

+0

Preferirei andare in modo @jelovirt: il test per None non è ambiguo e in realtà non aggiunge complessità. –

+0

Mi piacciono sempre le tuple Python per la restituzione di più valori. +1. – paxdiablo

+0

Mi piace questa idea, restituire un flag di controllo nello stesso campo valore non mi sembra corretto. In questo tipo di situazioni, si corre il rischio che in futuro i valori validi cambino (come hai detto, consentendo null) e il flag di controllo non sia più valido. – Sam

5

È possibile restituire la stringa se è arrivata in tempo oppure generare un'eccezione appropriata che indica il timeout.

+0

Anche se l'aumento di un'eccezione in Python è poco costoso rispetto ad altri linguaggi, non penso che fornire funzionalità che li utilizzano sia una grande idea. – Martin

+0

+1: le eccezioni hanno più senso in questo caso - si è verificata una condizione di "eccezione" - un timeout. –

+0

In effetti ho usato questo modello molto e con molto successo in un progetto che utilizza la comunicazione tramite porte seriali ecc. L'eccezione di timeout gestisce i tentativi, rispedendo le condizioni abbastanza bene. – Ber

10

Credo che il design ortodosso di Python sarebbe quello di restituire Nessuno. Il manual dice:

Nessuno

Questo tipo ha un singolo valore. C'è un singolo oggetto con questo valore.L'accesso all'oggetto avviene tramite il nome predefinito Nessuno. Viene utilizzato per per indicare l'assenza di un valore in molte situazioni , ad esempio, viene restituito dalle funzioni che non restituiscono esplicitamente lo nulla. Il suo valore di verità è falso.

2

Per aggiungere al punto di Ber, è possibile prendere in considerazione qualcos'altro. Se usi una stringa vuota o None, lasci la porta aperta per i bug della varietà "stupida". D'altra parte, se si alza un'eccezione, si sta forzando l'esecuzione di qualsiasi operazione in esecuzione per essere interrotta.

Ad esempio, si consideri il seguente codice:

result = MyFunc(s, timeout) 
if result[0] == 'a': 
    do_something() 

Ciò solleva un'eccezione se l'operazione è scaduta e ottenuto una stringa vuota o None. Quindi, dovreste cambiare la situazione a:

result = MyFunc(s, timeout) 
if result and result[0] == 'a': 
    do_something() 

Questi tipi di modifiche tendono ad aggiungere e rendere il codice più difficile da capire.

Naturalmente, sono sicuro che la tua risposta sarà qualcosa del tipo "Non lo farò" o "che non accadrà" a cui la mia risposta è "Anche se non fai" imbattersi in esso con questa funzione, alla fine, se si prende l'abitudine di fare questo ". Questi tipi di bug sono quasi sempre il risultato di casi d'angolo a cui di solito non si pensa.

1

Questo è un caso d'uso classico per i generatori Python. La parola chiave yield fornisce un modo semplice per iterare su insiemi discreti senza restituire il tutto in una sola volta:

def MyFunc(s, timeout) : 
    test = get_some_input(timeout) 
    while test.endswith(s) 
     yield test 
     test = get_some_input(timeout) 

for input in MyFunc(s, timeout): 
    print input 

La chiave qui è che non c'è alcun valore di ritorno per specificare la fine dell'input; invece, si raggiunge semplicemente la fine dell'iteratore. Ulteriori informazioni sui generatori here.

Problemi correlati