An alternate approach - the first/third options can be wrapped up:
def forward_none(func):
def wrapper(arg):
return None if arg is None else func(arg)
return wrapper
And keep in mind that methods don't have to be used as methods - they're still attributes of the class, and when looked up in the class, they're plain functions:
forward_none(str.upper)(foobar('foo'))
And we can also use this as a decorator:
@forward_none
def do_interesting_things(value):
# code that assumes value is not None...
do_interesting_things(None) # ignores the original code and evaluates to None
do_interesting_things("something") # as before decoration
Although in practice, if I had to, I would probably do what Martijn suggests. And I would try really hard not to have to; getting into this situation is a code smell suggesting that we should have raised an exception rather than returning None
in the first place. :)