If you are in the unfortunate situation where you must deal with a function that behaves like the one you presented, a clear way to handle it is with a try: statement.
try:
x, y, z = f()
except TypeError:
<handle the situation where False was returned>
This works because trying to unpack False raises a TypeError.
If you can modify the function, I might argue that the idiomatic strategy would be to raise an error (either built-in or custom) instead of returning False.
def f():
if condition1:
raise ValueError('Calling f() is invalid because condition1 evaluates to True')
return x, y, z
try:
x, y, z = f()
except ValueError:
<handle the situation where a tuple could not be returned>
This has the benefit of showing the true nature of the error in an uncaught traceback rather than the less obvious TypeError: 'bool' object is not iterable. It also has the benefit of giving consistent return types, so there is no confusion from the user.
Documentation becomes much clearer as well, because instead of
"in the case of success it will return a tuple of three elements, but in the case of failure it will return False (not as a tuple)"
the documentation becomes
"returns a tuple of three elements; raises a ValueError on failure"
(False,)in theTruecase andx,y,zin theFalsecase. Both tuples are "the same object type", but the original program still does not work, because the number of items is different.