Search code examples
pythonbuilt-inpython-internals

How does Python distinguish explicitly passed None as argument in built-ins


I experimented with the next code:

>>> f = object()

# It's obvious behavior:
>>> f.foo
Traceback (most recent call last):       
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'foo'

# However, the next one is surprising me!
>>> getattr(f, 'foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'foo'

# And this one returns None as expected:
>>> getattr(f, 'foo', None)

Then I found this pseudo-signature of getattr() in the PyCharm IDE:

def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value

    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    """
    pass

My question is how does python distinguish this two scenarios of using getattr() (and maybe other functions) internally? And is it possible to do something similar entirely in the client side code?


Solution

  • As @scytale said, the pseudo-signature of getattr doesn't quite correspond to its implementations. I've seen attempts to replicate the behaviour in pure Python that look something like this:

    class MyObject(object):
        __marker = object()
    
        def getvalue(key, default=__marker):
            ...
            if key is __marker:
                 # no value supplied for default
                 ....
    

    In other words, use a marker value that a caller cannot easily supply to check if no value was given as the default rather than None.