Tutorial :Python : is it ok returning both boolean and string?



Question:

Original Question

I have made a function which is waiting for a particular string to appear on a serial port, and returns all character read until the string was found, or false if not. This is quite convenient, but I was wondering if it is considered bad practice or not ?

Clarification :

The primary goal is to wait for a particular string to appear in a given amount of time. Except for IO error, the possible outcome is True (the string did appear) or False The secondary goal is to get the entire output, because there might be information that I would like to parse for before the actual answer that is looked for. I thought may be I could combine the primary and secondary goal in one return value.

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

Edit : Another proposed answer is to raise an exception. I don't think it is a good idea, because the timeout is an expected behaviour. I mean, if there is a parameter for specifying a timeout, then a timeout is a possible outcome, and not an exception.

Edit 2 : Since I need to store the input, maybe using a class is the right solution. The wait for function has a clear return value, yet the entire string that was read until timeout is also accessible.

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  


Solution:1

It would be better to return a string AND a boolean (as in the title) instead of returning a string OR a boolean. You shouldn't have to figure out what the return value means. It should be totally explicit and orthogonal issues should be separated into different variables.

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

I tend not to return tuples a lot, because it feels funny. But it's perfectly valid to do so.

Returning "None" is a valid solution, already mentioned here.


Solution:2

Would it not be more suitable to return a None instead of False?


Solution:3

I believe the orthodox Python design would be to return None. The manual says:

None

This type has a single value. There is a single object with this value. This object is accessed through the built-in name None. It is used to signify the absence of a value in many situations, e.g., it is returned from functions that don’t explicitly return anything. Its truth value is false.


Solution:4

You could return the string if it arrived in time, or raise a suitable exception indicating time out.


Solution:5

The convenient thing is to return an empty string in this case.

Besides an empty string in Python will evaluate to False anyway. So you could call it like:

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

Addition: As pointed out by S.Lott the true Pythonic way is to return None. Though I choose to return strings in string related funcs. A matter of preference indeed.

Also I assume the caller of Myfunc only cares about getting a string to manipulate on - empty or not. If the caller needs to check about timeout issues, etc.. it's better to use exceptions or returning None.


Solution:6

Maybe if you return a tuple like (False, None) and (True, test) it would be better, as you can evaluate them separatedly and not add unnecesary complexity.

EDIT: Perhaps the string that appeared on the serial port is "" (maybe expected), so returning True can say that it arrived that way.


Solution:7

To add to Ber's point, you might want to take something else into account. If you use an empty string or None, you leave the door open for bugs of the "dumb" variety. On the other hand, if you raise an exception, you're forcing the execution of whatever operation is running to be aborted.

For example, consider the following code:

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

This will raise an exception if the operation timed out and got either an empty string or None. So you'd have to change that to:

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

These kinds of changes tend to add up and make your code more difficult to understand.

Of course, I'm sure that your answer to this will be something along the lines of "I won't do that" or "that won't happen" to which my answer is "Even if you don't run into it with this function, you will eventually if you make a habit of doing this." These kinds of bugs are almost always the result of corner cases that you don't usually think about.


Solution:8

This is a classic use case for Python generators. The yield keyword provides a simple way to iterate over discrete sets without returning the whole thing at once:

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  

The key here is there is no return value to specify the end of input; instead, you simply reach the end of the iterator. More information on generators here.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »