How to distinguish default argument and argument provided with default value?

Viewed 202

Say I have function f as follows:

def f(c=None):
    return 42 if c is None else c

Then I can't get None out of this function. Now you could think "well, just check for another value like 2128.213 or whatever" but then I can't get that specific value out of the function can I?

That's why I'd like to distinguish, if possible, between f() and f(None) so that I can have

f() -> 42
f(None)-> None

Bear in mind this is a simplified example. In practice it's a class's __init__(...) function with multiple positional arguments which I'd like to handle as c in this example.

2 Answers

The common practice in such cases is to use specific sentinel value you never want to return.

class Sentinel():
    pass


_sentinel = Sentinel()

# _sentinel = object()  # this is the option too

def f(x=_sentinel):
    return 42 if x is _sentinel else x

assert f() == 42
assert f(None) is None
assert f(5) == 5

You can make use of Python's private attributes : Assign a new object to that private attribute, compare if the argument is the private object, and done.

class somename:
    __default = object()
    def __init__(self, default=__default):
        print(42 if default is self.__default else default)

somename()
somename(default=12)
Related