Creating objects to be added to a list When creating objects to be added to a list in Python, we can avoid the if statement by changing our create_object function to return a list.

Is this a good idea or not? Why?

(assume create_object is called in multiple places and is always added to a list)

def _create_object(self, data):
  if data:
    return Object(data)

if _create_object(data):
  mylist.append(_create_object(data))


or

def _create_object(self, data):
  if data:
    return [Object(data)]
  return []

# Now we no longer need the if
mylist += _create_object(data)


or (late addition) should we be using exceptions:

def _create_object(self, data):
  if data:
    return Object(data)
  raise BadDataException()

try:
  mylist.append(_create_object(data))
except BadDataException:
  pass
Avoiding an if statement is not a useful goal. Occasionally it is the correct means towards a goal, such as making code easier to write or to understand. Thus I think your question is too narrowly focused, or oversimplified. The problem here is that the wrapper function _create_object is too simple to merit being its own function, and the complexity outside of it matches that inside.

Let's consider some small transformations of this. First we'll take the if data outside of _create_object. I do this because I find the current implementation is close to do-what-I-mean. This may have been less true if the conditions were more intricate.

def _create_object(data):
    return Object(data)

if data:
    mylist.append(_create_object(data))


From there it's pretty obvious that _create_object is another spelling of Object, and the final transformation is to just remove the wrapper:

if data:
    mylist.append(Object(data))


Let's take a step further back and assume you're pulling subsequent values of data from a list that I'll call data_source. You can avoid the kind of if statement you had before by writing either a list comprehension (with embedded if), or using filter:

mylist += [Object(data) for data in data_source if data]
# or
mylist += [Object(data) for data in filter(None, data_source)]
# or, if _create_object's conditions are too complex for this transformation
mylist += [_create_object(data) for data in data_source if _create_object(data)]
# or, two-layers
mylist += filter(None, [_create_object(data) for data in data_source])


Note that I don't particularly like the third as it calls _create_object twice per item, but the fourth one requires your second wrapper - the one that returns None.

As for whether you should be using exceptions, the answer is two-fold. If you're dealing with a large number of false values in data, and this is in an inner loop, performance could be a problem. In cases like that, it can make sense to implement the look-before-you-leap semantics of your other examples. However, if Object cannot reasonably construct itself from a false data parameter, it should itself raise an exception. That way if a given caller doesn't check first, it will result in a clear fixable error.