Search code examples
pythonbuilt-infunction-definitionellipsis

What is the meaning of "..." in a python function body?


Whenever I see any python builtin function, I always find a function that has ..., for example:

def append(self, __object: _T) -> None: ...

But, what does ... mean?


Solution

  • ... is the literal for the object named Ellipsis, which used to exist only for special kinds of slicing (e.g. in numpy). It's a singleton object, like None and NotImplemented.

    Because ... means you're eliding or leaving something out in normal writing, the literal sometimes gets used for that same purpose in Python code. If you're teaching somebody how to write a function, you might show them the def statement like this:

    def foo(bar):
        ...
    

    Here the ... doesn't do anything useful, it just shows where you left out the body of the function. The more traditional way of doing nothing is the pass statement, but ... seems to be taking over, perhaps especially for when the function should have a body, you're just not showing it.

    This usage became common among users of type hinting. It is often necessary to write "stub" functions that show the types of arguments expected by functions written in third party libraries when their authors didn't use type hinting. Stubs don't need a full function body, so ... gets put instead.

    Since type hinting was introduced as an optional feature of Python, the interpreter didn't include type hints in its own code for the standard library, so stub files had to be created for all of the functions and methods of the builtins and the standard library. A lot of the features of stub formatting have been reused in various bits of documentation, since it concisely shows what types are expected by a function.

    There's only one specific situation where ... has a special meaning in type hinting, that's for Callable. You can hint Callable[..., int] to refer to a value that is a callable object with unspecified parameters that returns an integer. This is only done because it's often awkward to hint all of a callable's arguments properly, especially for a function that can be called a bunch of different ways. There's been talk about adding new syntax for hinting Callable more directly, but it hasn't been nailed down yet (PEP 677 proposed (int, str) -> bool to mean Callable[[int, str], bool], but it was rejected last December).