I’ve recently had a nerdy discussion with a colleague during
a code review about when to use Pythons pass statement
vs. the ellipsis literal ....
You’ve probably seen the pass statement in Python code
as a means to indicate that a block is intentionally left empty
to avoid a SyntaxError.
Like in the following except block where we expect
that an exception might be raised but just want to ignore it:
try:
client.get(id=42)
except ApiException:
pass
Somehow the ellipsis literal ... has gotten
some hype lately and some people started doing this:
try:
client.get(id=42)
except ApiException:
...
While this is syntactically valid Python code the semantics
are weird to me.
To me, the pass statement effectively communicates
that we should just pass this block without running any code at all.
While the ... are more like
"there is something to be expected here in the future”.
Therefore, the ... can be thought of a placeholder.
Whenever I see the ... my head auto-plays a
Dun Dun Dun sound effect - to emphasize the suspension of code.
It would be a pity if it’s a suspension of code until all eternity
if you use at as a pass replacement.
Where should I use the ...?
As I’ve already mentioned you should use the ...
as a placeholder where eventually some could should appear,
but you don’t necessarily want to raise NotImplementedError.
A similar situation where I use it is with Pythons
Abstract Base Classes to indicate that the function body needs
to be implemented by a subclass.
from abc import abstractmethod
class AbstractEventLoop:
@abstractmethod
def run(self, ...):
...
The next place where I use it is in Python stub files to indicate
an ignored function body:
def get(id: int) -> Model: ...
The fourth place is in extended slicing with custom container types,
for what the ... was originally introduced for.
For example, the numpy array indexing supports it:
from numpy import arange
a = arange(16).reshape(2, 2, 2, 2)
flat_a = a[..., 0].flatten()
But what is the ... literal ?
The ellipsis literal ... is syntactic sugar
for the Ellipsis object, which is the sole instance
of the types.EllipsisType type.
You can use it like every other object in Python,
except that you can’t create a new one.
Thus, when you override it
(yes, that’s possible: __builtins__.Ellipsis = 42)
you can’t really get it back - thus, don’t do it.